• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 import android.view.LayoutInflater;
23 import android.view.View;
24 import android.view.ViewGroup;
25 
26 import androidx.appcompat.app.AlertDialog;
27 import androidx.preference.Preference;
28 import androidx.preference.Preference.OnPreferenceChangeListener;
29 import androidx.preference.Preference.OnPreferenceClickListener;
30 import androidx.preference.SwitchPreference;
31 
32 import com.android.settings.R;
33 import com.android.settings.applications.AppInfoWithHeader;
34 import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
35 import com.android.settings.applications.AppStateManageExternalStorageBridge;
36 import com.android.settings.overlay.FeatureFactory;
37 import com.android.settingslib.applications.ApplicationsState.AppEntry;
38 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
39 
40 /**
41  * Class for displaying app info related to {@link AppOpsManager#OP_MANAGE_EXTERNAL_STORAGE}.
42  */
43 public class ManageExternalStorageDetails extends AppInfoWithHeader implements
44         OnPreferenceChangeListener, OnPreferenceClickListener {
45 
46     private static final String KEY_APP_OPS_SETTINGS_SWITCH = "app_ops_settings_switch";
47 
48     private AppStateManageExternalStorageBridge mBridge;
49     private AppOpsManager mAppOpsManager;
50     private SwitchPreference mSwitchPref;
51     private PermissionState mPermissionState;
52     private MetricsFeatureProvider mMetricsFeatureProvider;
53 
54     @Override
onCreate(Bundle savedInstanceState)55     public void onCreate(Bundle savedInstanceState) {
56         super.onCreate(savedInstanceState);
57 
58         Context context = getActivity();
59         mBridge = new AppStateManageExternalStorageBridge(context, mState, null);
60         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
61 
62         // initialize preferences
63         addPreferencesFromResource(R.xml.manage_external_storage_permission_details);
64         mSwitchPref = findPreference(KEY_APP_OPS_SETTINGS_SWITCH);
65 
66         // install event listeners
67         mSwitchPref.setOnPreferenceChangeListener(this);
68 
69         mMetricsFeatureProvider =
70                 FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider();
71     }
72 
73     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)74     public View onCreateView(LayoutInflater inflater,
75             ViewGroup container,
76             Bundle savedInstanceState) {
77         // if we don't have a package info, show a page saying this is unsupported
78         if (mPackageInfo == null) {
79             return inflater.inflate(R.layout.manage_applications_apps_unsupported, null);
80         }
81         return super.onCreateView(inflater, container, savedInstanceState);
82     }
83 
84     @Override
onDestroy()85     public void onDestroy() {
86         super.onDestroy();
87         mBridge.release();
88     }
89 
90     @Override
onPreferenceClick(Preference preference)91     public boolean onPreferenceClick(Preference preference) {
92         return false;
93     }
94 
95     @Override
onPreferenceChange(Preference preference, Object newValue)96     public boolean onPreferenceChange(Preference preference, Object newValue) {
97         if (preference == mSwitchPref) {
98             if (mPermissionState != null && !newValue.equals(mPermissionState.isPermissible())) {
99                 setManageExternalStorageState((Boolean) newValue);
100                 refreshUi();
101             }
102             return true;
103         }
104         return false;
105     }
106 
107     /**
108      * Toggles {@link AppOpsManager#OP_MANAGE_EXTERNAL_STORAGE} for the app.
109      */
setManageExternalStorageState(boolean newState)110     private void setManageExternalStorageState(boolean newState) {
111         logSpecialPermissionChange(newState, mPackageName);
112         mAppOpsManager.setUidMode(AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE,
113                 mPackageInfo.applicationInfo.uid, newState
114                         ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_ERRORED);
115     }
116 
logSpecialPermissionChange(boolean newState, String packageName)117     private void logSpecialPermissionChange(boolean newState, String packageName) {
118         int logCategory = newState ? SettingsEnums.APP_SPECIAL_PERMISSION_MANAGE_EXT_STRG_ALLOW
119                 : SettingsEnums.APP_SPECIAL_PERMISSION_MANAGE_EXT_STRG_DENY;
120 
121         mMetricsFeatureProvider.action(
122                 mMetricsFeatureProvider.getAttribution(getActivity()),
123                 logCategory,
124                 getMetricsCategory(),
125                 packageName,
126                 0 /* value */);
127     }
128 
129     @Override
refreshUi()130     protected boolean refreshUi() {
131         if (mPackageInfo == null) {
132             return true;
133         }
134 
135         mPermissionState = mBridge.getManageExternalStoragePermState(mPackageName,
136                 mPackageInfo.applicationInfo.uid);
137 
138         mSwitchPref.setChecked(mPermissionState.isPermissible());
139 
140         // you cannot ask a user to grant you a permission you did not have!
141         mSwitchPref.setEnabled(mPermissionState.permissionDeclared);
142 
143         return true;
144     }
145 
146     @Override
createDialog(int id, int errorCode)147     protected AlertDialog createDialog(int id, int errorCode) {
148         return null;
149     }
150 
151     @Override
getMetricsCategory()152     public int getMetricsCategory() {
153         return SettingsEnums.MANAGE_EXTERNAL_STORAGE;
154     }
155 
156     /**
157      * Returns the string that states whether whether the app has access to
158      * {@link AppOpsManager#OP_MANAGE_EXTERNAL_STORAGE}.
159      * <p>This string is used in the "All files access" page that displays all apps requesting
160      * {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
161      */
getSummary(Context context, AppEntry entry)162     public static CharSequence getSummary(Context context, AppEntry entry) {
163         final PermissionState state;
164         if (entry.extraInfo instanceof PermissionState) {
165             state = (PermissionState) entry.extraInfo;
166         } else {
167             state = new AppStateManageExternalStorageBridge(context, null, null)
168                     .getManageExternalStoragePermState(entry.info.packageName, entry.info.uid);
169         }
170 
171         return getSummary(context, state);
172     }
173 
getSummary(Context context, PermissionState state)174     private static CharSequence getSummary(Context context, PermissionState state) {
175         return context.getString(state.isPermissible()
176                 ? R.string.app_permission_summary_allowed
177                 : R.string.app_permission_summary_not_allowed);
178     }
179 }
180