1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.settings.applications.appinfo;
17 
18 import static android.app.Activity.RESULT_CANCELED;
19 import static android.app.Activity.RESULT_OK;
20 import static android.app.AppOpsManager.MODE_ALLOWED;
21 import static android.app.AppOpsManager.MODE_ERRORED;
22 
23 import android.app.AppOpsManager;
24 import android.app.settings.SettingsEnums;
25 import android.content.Context;
26 import android.os.Bundle;
27 
28 import androidx.appcompat.app.AlertDialog;
29 import androidx.preference.Preference;
30 import androidx.preference.Preference.OnPreferenceChangeListener;
31 import androidx.preference.TwoStatePreference;
32 
33 import com.android.settings.R;
34 import com.android.settings.Settings;
35 import com.android.settings.applications.AppInfoWithHeader;
36 import com.android.settings.applications.AppStateAppOpsBridge;
37 import com.android.settings.applications.AppStateTurnScreenOnBridge;
38 import com.android.settingslib.applications.ApplicationsState;
39 
40 /**
41  * Detail page for turn screen on special app access.
42  */
43 public class TurnScreenOnDetails extends AppInfoWithHeader implements OnPreferenceChangeListener {
44 
45     private static final String KEY_APP_OPS_SETTINGS_SWITCH = "app_ops_settings_switch";
46 
47     private AppStateTurnScreenOnBridge mAppBridge;
48     private AppOpsManager mAppOpsManager;
49     private TwoStatePreference mSwitchPref;
50     private AppStateAppOpsBridge.PermissionState mPermissionState;
51 
52 
53     @Override
onCreate(Bundle savedInstanceState)54     public void onCreate(Bundle savedInstanceState) {
55         super.onCreate(savedInstanceState);
56 
57         final Context context = getActivity();
58         mAppBridge = new AppStateTurnScreenOnBridge(context, mState, /*callback=*/ null);
59         mAppOpsManager = context.getSystemService(AppOpsManager.class);
60 
61         // find preferences
62         addPreferencesFromResource(R.xml.turn_screen_on_permissions_details);
63         mSwitchPref = (TwoStatePreference) findPreference(KEY_APP_OPS_SETTINGS_SWITCH);
64         mSwitchPref.setOnPreferenceChangeListener(this);
65     }
66 
67     @Override
onPreferenceChange(Preference preference, Object newValue)68     public boolean onPreferenceChange(Preference preference, Object newValue) {
69         final boolean checked = (Boolean) newValue;
70         if (preference == mSwitchPref) {
71             if (mPermissionState != null && checked != mPermissionState.isPermissible()) {
72                 if (Settings.TurnScreenOnSettingsActivity.class.getName().equals(
73                         getIntent().getComponent().getClassName())) {
74                     setResult(checked ? RESULT_OK : RESULT_CANCELED);
75                 }
76                 setCanTurnScreenOn(checked);
77                 refreshUi();
78             }
79             return true;
80         }
81         return false;
82     }
83 
84     @Override
refreshUi()85     protected boolean refreshUi() {
86         if (mPackageInfo == null || mPackageInfo.applicationInfo == null) {
87             return false;
88         }
89         mPermissionState = mAppBridge.getPermissionInfo(mPackageName,
90                 mPackageInfo.applicationInfo.uid);
91         mSwitchPref.setEnabled(mPermissionState.permissionDeclared);
92         mSwitchPref.setChecked(mPermissionState.isPermissible());
93         return true;
94     }
95 
96     @Override
createDialog(int id, int errorCode)97     protected AlertDialog createDialog(int id, int errorCode) {
98         return null;
99     }
100 
101     @Override
getMetricsCategory()102     public int getMetricsCategory() {
103         return SettingsEnums.SETTINGS_MANAGE_TURN_SCREEN_ON;
104     }
105 
106     /**
107      * Sets whether the app associated with the given {@code packageName} is allowed to turn the
108      * screen on.
109      */
setCanTurnScreenOn(boolean newState)110     void setCanTurnScreenOn(boolean newState) {
111         mAppOpsManager.setUidMode(AppOpsManager.OPSTR_TURN_SCREEN_ON,
112                 mPackageInfo.applicationInfo.uid, newState ? MODE_ALLOWED : MODE_ERRORED);
113     }
114 
115     /**
116      * @return the summary for the current state of whether the app associated with the given
117      * packageName is allowed to turn the screen on.
118      */
getSummary(Context context, ApplicationsState.AppEntry entry)119     public static int getSummary(Context context, ApplicationsState.AppEntry entry) {
120         final AppStateAppOpsBridge.PermissionState state;
121         if (entry.extraInfo instanceof AppStateAppOpsBridge.PermissionState) {
122             state = (AppStateAppOpsBridge.PermissionState) entry.extraInfo;
123         } else {
124             state = new AppStateTurnScreenOnBridge(context, /*appState=*/ null,
125                     /*callback=*/ null).getPermissionInfo(entry.info.packageName, entry.info.uid);
126         }
127         return state.isPermissible() ? R.string.app_permission_summary_allowed
128                 : R.string.app_permission_summary_not_allowed;
129     }
130 }
131