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