1 /*
2  * Copyright (C) 2015 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 android.app.AppOpsManager;
19 import android.app.settings.SettingsEnums;
20 import android.content.Context;
21 import android.os.Bundle;
22 
23 import androidx.appcompat.app.AlertDialog;
24 import androidx.preference.Preference;
25 import androidx.preference.Preference.OnPreferenceChangeListener;
26 import androidx.preference.Preference.OnPreferenceClickListener;
27 import androidx.preference.TwoStatePreference;
28 
29 import com.android.settings.R;
30 import com.android.settings.applications.AppInfoWithHeader;
31 import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
32 import com.android.settings.applications.AppStateWriteSettingsBridge;
33 import com.android.settings.applications.AppStateWriteSettingsBridge.WriteSettingsState;
34 import com.android.settings.overlay.FeatureFactory;
35 import com.android.settingslib.applications.ApplicationsState.AppEntry;
36 
37 public class WriteSettingsDetails extends AppInfoWithHeader implements OnPreferenceChangeListener,
38         OnPreferenceClickListener {
39 
40     private static final String KEY_APP_OPS_SETTINGS_SWITCH = "app_ops_settings_switch";
41 
42     // Use a bridge to get the overlay details but don't initialize it to connect with all state.
43     // TODO: Break out this functionality into its own class.
44     private AppStateWriteSettingsBridge mAppBridge;
45     private AppOpsManager mAppOpsManager;
46     private TwoStatePreference mSwitchPref;
47     private WriteSettingsState mWriteSettingsState;
48 
49     @Override
onCreate(Bundle savedInstanceState)50     public void onCreate(Bundle savedInstanceState) {
51         super.onCreate(savedInstanceState);
52 
53         Context context = getActivity();
54         mAppBridge = new AppStateWriteSettingsBridge(context, mState, null);
55         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
56 
57         addPreferencesFromResource(R.xml.write_system_settings_permissions_details);
58         mSwitchPref = findPreference(KEY_APP_OPS_SETTINGS_SWITCH);
59 
60         mSwitchPref.setOnPreferenceChangeListener(this);
61 
62     }
63 
64     @Override
onPreferenceClick(Preference preference)65     public boolean onPreferenceClick(Preference preference) {
66         return false;
67     }
68 
69     @Override
onPreferenceChange(Preference preference, Object newValue)70     public boolean onPreferenceChange(Preference preference, Object newValue) {
71         if (preference == mSwitchPref) {
72             if (mWriteSettingsState != null && (Boolean) newValue != mWriteSettingsState
73                     .isPermissible()) {
74                 setCanWriteSettings(!mWriteSettingsState.isPermissible());
75                 refreshUi();
76             }
77             return true;
78         }
79         return false;
80     }
81 
setCanWriteSettings(boolean newState)82     private void setCanWriteSettings(boolean newState) {
83         logSpecialPermissionChange(newState, mPackageName);
84         mAppOpsManager.setMode(AppOpsManager.OP_WRITE_SETTINGS,
85                 mPackageInfo.applicationInfo.uid, mPackageName, newState
86                 ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_ERRORED);
87     }
88 
logSpecialPermissionChange(boolean newState, String packageName)89     void logSpecialPermissionChange(boolean newState, String packageName) {
90         int logCategory = newState ? SettingsEnums.APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_ALLOW
91                 : SettingsEnums.APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_DENY;
92         FeatureFactory.getFeatureFactory().getMetricsFeatureProvider().action(getContext(),
93                 logCategory, packageName);
94     }
95 
96     @Override
refreshUi()97     protected boolean refreshUi() {
98         mWriteSettingsState = mAppBridge.getWriteSettingsInfo(mPackageName,
99                 mPackageInfo.applicationInfo.uid);
100 
101         boolean canWrite = mWriteSettingsState.isPermissible();
102         mSwitchPref.setChecked(canWrite);
103         // you can't ask a user for a permission you didn't even declare!
104         mSwitchPref.setEnabled(mWriteSettingsState.permissionDeclared);
105 
106         return true;
107     }
108 
109     @Override
createDialog(int id, int errorCode)110     protected AlertDialog createDialog(int id, int errorCode) {
111         return null;
112     }
113 
114     @Override
getMetricsCategory()115     public int getMetricsCategory() {
116         return SettingsEnums.MODIFY_SYSTEM_SETTINGS;
117     }
118 
getSummary(Context context, AppEntry entry)119     public static CharSequence getSummary(Context context, AppEntry entry) {
120         WriteSettingsState state;
121         if (entry.extraInfo instanceof WriteSettingsState) {
122             state = (WriteSettingsState) entry.extraInfo;
123         } else if (entry.extraInfo instanceof PermissionState) {
124             state = new WriteSettingsState((PermissionState) entry.extraInfo);
125         } else {
126             state = new AppStateWriteSettingsBridge(context, null, null).getWriteSettingsInfo(
127                     entry.info.packageName, entry.info.uid);
128         }
129 
130         return getSummary(context, state);
131     }
132 
getSummary(Context context, WriteSettingsState writeSettingsState)133     public static CharSequence getSummary(Context context, WriteSettingsState writeSettingsState) {
134         return context.getString(writeSettingsState.isPermissible()
135                 ? R.string.app_permission_summary_allowed
136                 : R.string.app_permission_summary_not_allowed);
137     }
138 }
139