WriteSettingsDetails.java revision e8ffc29f7fa67a607553b4cb7512887845f4af82
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 */ 16package com.android.settings.applications.appinfo; 17 18import android.app.AlertDialog; 19import android.app.AppOpsManager; 20import android.content.ActivityNotFoundException; 21import android.content.Context; 22import android.content.Intent; 23import android.content.pm.PackageManager; 24import android.content.pm.ResolveInfo; 25import android.os.Bundle; 26import android.os.UserHandle; 27import android.provider.Settings; 28import android.support.v14.preference.SwitchPreference; 29import android.support.v7.preference.Preference; 30import android.support.v7.preference.Preference.OnPreferenceChangeListener; 31import android.support.v7.preference.Preference.OnPreferenceClickListener; 32import android.util.Log; 33 34import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 35import com.android.settings.R; 36import com.android.settings.applications.AppInfoWithHeader; 37import com.android.settings.applications.AppStateAppOpsBridge.PermissionState; 38import com.android.settings.applications.AppStateWriteSettingsBridge; 39import com.android.settings.applications.AppStateWriteSettingsBridge.WriteSettingsState; 40import com.android.settings.overlay.FeatureFactory; 41import com.android.settingslib.applications.ApplicationsState.AppEntry; 42 43public class WriteSettingsDetails extends AppInfoWithHeader implements OnPreferenceChangeListener, 44 OnPreferenceClickListener { 45 46 private static final String KEY_APP_OPS_PREFERENCE_SCREEN = "app_ops_preference_screen"; 47 private static final String KEY_APP_OPS_SETTINGS_SWITCH = "app_ops_settings_switch"; 48 private static final String LOG_TAG = "WriteSettingsDetails"; 49 50 private static final int [] APP_OPS_OP_CODE = { 51 AppOpsManager.OP_WRITE_SETTINGS 52 }; 53 54 // Use a bridge to get the overlay details but don't initialize it to connect with all state. 55 // TODO: Break out this functionality into its own class. 56 private AppStateWriteSettingsBridge mAppBridge; 57 private AppOpsManager mAppOpsManager; 58 private SwitchPreference mSwitchPref; 59 private Intent mSettingsIntent; 60 private WriteSettingsState mWriteSettingsState; 61 62 @Override 63 public void onCreate(Bundle savedInstanceState) { 64 super.onCreate(savedInstanceState); 65 66 Context context = getActivity(); 67 mAppBridge = new AppStateWriteSettingsBridge(context, mState, null); 68 mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 69 70 addPreferencesFromResource(R.xml.write_system_settings_permissions_details); 71 mSwitchPref = (SwitchPreference) findPreference(KEY_APP_OPS_SETTINGS_SWITCH); 72 73 mSwitchPref.setOnPreferenceChangeListener(this); 74 75 mSettingsIntent = new Intent(Intent.ACTION_MAIN) 76 .addCategory(Settings.INTENT_CATEGORY_USAGE_ACCESS_CONFIG) 77 .setPackage(mPackageName); 78 } 79 80 @Override 81 public boolean onPreferenceClick(Preference preference) { 82 return false; 83 } 84 85 @Override 86 public boolean onPreferenceChange(Preference preference, Object newValue) { 87 if (preference == mSwitchPref) { 88 if (mWriteSettingsState != null && (Boolean) newValue != mWriteSettingsState 89 .isPermissible()) { 90 setCanWriteSettings(!mWriteSettingsState.isPermissible()); 91 refreshUi(); 92 } 93 return true; 94 } 95 return false; 96 } 97 98 private void setCanWriteSettings(boolean newState) { 99 logSpecialPermissionChange(newState, mPackageName); 100 mAppOpsManager.setMode(AppOpsManager.OP_WRITE_SETTINGS, 101 mPackageInfo.applicationInfo.uid, mPackageName, newState 102 ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_ERRORED); 103 } 104 105 void logSpecialPermissionChange(boolean newState, String packageName) { 106 int logCategory = newState ? MetricsEvent.APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_ALLOW 107 : MetricsEvent.APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_DENY; 108 FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider().action(getContext(), 109 logCategory, packageName); 110 } 111 112 private boolean canWriteSettings(String pkgName) { 113 int result = mAppOpsManager.noteOpNoThrow(AppOpsManager.OP_WRITE_SETTINGS, 114 mPackageInfo.applicationInfo.uid, pkgName); 115 if (result == AppOpsManager.MODE_ALLOWED) { 116 return true; 117 } 118 119 return false; 120 } 121 122 @Override 123 protected boolean refreshUi() { 124 mWriteSettingsState = mAppBridge.getWriteSettingsInfo(mPackageName, 125 mPackageInfo.applicationInfo.uid); 126 127 boolean canWrite = mWriteSettingsState.isPermissible(); 128 mSwitchPref.setChecked(canWrite); 129 // you can't ask a user for a permission you didn't even declare! 130 mSwitchPref.setEnabled(mWriteSettingsState.permissionDeclared); 131 132 ResolveInfo resolveInfo = mPm.resolveActivityAsUser(mSettingsIntent, 133 PackageManager.GET_META_DATA, mUserId); 134 return true; 135 } 136 137 @Override 138 protected AlertDialog createDialog(int id, int errorCode) { 139 return null; 140 } 141 142 @Override 143 public int getMetricsCategory() { 144 return MetricsEvent.SYSTEM_ALERT_WINDOW_APPS; 145 } 146 147 public static CharSequence getSummary(Context context, AppEntry entry) { 148 WriteSettingsState state; 149 if (entry.extraInfo instanceof WriteSettingsState) { 150 state = (WriteSettingsState) entry.extraInfo; 151 } else if (entry.extraInfo instanceof PermissionState) { 152 state = new WriteSettingsState((PermissionState) entry.extraInfo); 153 } else { 154 state = new AppStateWriteSettingsBridge(context, null, null).getWriteSettingsInfo( 155 entry.info.packageName, entry.info.uid); 156 } 157 158 return getSummary(context, state); 159 } 160 161 public static CharSequence getSummary(Context context, WriteSettingsState writeSettingsState) { 162 return context.getString(writeSettingsState.isPermissible() 163 ? R.string.app_permission_summary_allowed 164 : R.string.app_permission_summary_not_allowed); 165 } 166} 167