UsageAccessDetails.java revision 265d3c2a0c36251bf8a9f571d7239b6dd404d942
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;
17
18import android.app.AlertDialog;
19import android.app.AppOpsManager;
20import android.app.admin.DevicePolicyManager;
21import android.content.ActivityNotFoundException;
22import android.content.ComponentName;
23import android.content.Context;
24import android.content.Intent;
25import android.content.pm.PackageManager;
26import android.content.pm.ResolveInfo;
27import android.os.Bundle;
28import android.os.UserHandle;
29import android.provider.Settings;
30import android.support.v14.preference.SwitchPreference;
31import android.support.v7.preference.Preference;
32import android.support.v7.preference.Preference.OnPreferenceChangeListener;
33import android.support.v7.preference.Preference.OnPreferenceClickListener;
34import android.util.Log;
35
36import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
37import com.android.settings.R;
38import com.android.settings.applications.AppStateUsageBridge.UsageState;
39
40public class UsageAccessDetails extends AppInfoWithHeader implements OnPreferenceChangeListener,
41        OnPreferenceClickListener {
42
43    private static final String KEY_APP_OPS_PREFERENCE_SCREEN = "app_ops_preference_screen";
44    private static final String KEY_APP_OPS_SETTINGS_SWITCH = "app_ops_settings_switch";
45    private static final String KEY_APP_OPS_SETTINGS_PREFS = "app_ops_settings_preference";
46    private static final String KEY_APP_OPS_SETTINGS_DESC = "app_ops_settings_description";
47
48    // Use a bridge to get the usage stats but don't initialize it to connect with all state.
49    // TODO: Break out this functionality into its own class.
50    private AppStateUsageBridge mUsageBridge;
51    private AppOpsManager mAppOpsManager;
52    private SwitchPreference mSwitchPref;
53    private Preference mUsagePrefs;
54    private Preference mUsageDesc;
55    private Intent mSettingsIntent;
56    private UsageState mUsageState;
57    private DevicePolicyManager mDpm;
58
59    @Override
60    public void onCreate(Bundle savedInstanceState) {
61        super.onCreate(savedInstanceState);
62
63        Context context = getActivity();
64        mUsageBridge = new AppStateUsageBridge(context, mState, null);
65        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
66        mDpm = context.getSystemService(DevicePolicyManager.class);
67
68        addPreferencesFromResource(R.xml.app_ops_permissions_details);
69        mSwitchPref = (SwitchPreference) findPreference(KEY_APP_OPS_SETTINGS_SWITCH);
70        mUsagePrefs = findPreference(KEY_APP_OPS_SETTINGS_PREFS);
71        mUsageDesc = findPreference(KEY_APP_OPS_SETTINGS_DESC);
72
73        getPreferenceScreen().setTitle(R.string.usage_access);
74        mSwitchPref.setTitle(R.string.permit_usage_access);
75        mUsagePrefs.setTitle(R.string.app_usage_preference);
76        mUsageDesc.setSummary(R.string.usage_access_description);
77
78        mSwitchPref.setOnPreferenceChangeListener(this);
79        mUsagePrefs.setOnPreferenceClickListener(this);
80
81        mSettingsIntent = new Intent(Intent.ACTION_MAIN)
82                .addCategory(Settings.INTENT_CATEGORY_USAGE_ACCESS_CONFIG)
83                .setPackage(mPackageName);
84    }
85
86    @Override
87    public boolean onPreferenceClick(Preference preference) {
88        if (preference == mUsagePrefs) {
89            if (mSettingsIntent != null) {
90                try {
91                    getActivity().startActivityAsUser(mSettingsIntent, new UserHandle(mUserId));
92                } catch (ActivityNotFoundException e) {
93                    Log.w(TAG, "Unable to launch app usage access settings " + mSettingsIntent, e);
94                }
95            }
96            return true;
97        }
98        return false;
99    }
100
101    @Override
102    public boolean onPreferenceChange(Preference preference, Object newValue) {
103        if (preference == mSwitchPref) {
104            if (mUsageState != null && (Boolean) newValue != mUsageState.isPermissible()) {
105                if (mUsageState.isPermissible() && mDpm.isProfileOwnerApp(mPackageName)) {
106                    new AlertDialog.Builder(getContext())
107                            .setIcon(com.android.internal.R.drawable.ic_dialog_alert_material)
108                            .setTitle(android.R.string.dialog_alert_title)
109                            .setMessage(R.string.work_profile_usage_access_warning)
110                            .setPositiveButton(R.string.okay, null)
111                            .show();
112                }
113                setHasAccess(!mUsageState.isPermissible());
114                refreshUi();
115            }
116            return true;
117        }
118        return false;
119    }
120
121    private void setHasAccess(boolean newState) {
122        mAppOpsManager.setMode(AppOpsManager.OP_GET_USAGE_STATS, mPackageInfo.applicationInfo.uid,
123                mPackageName, newState ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
124    }
125
126    @Override
127    protected boolean refreshUi() {
128        mUsageState = mUsageBridge.getUsageInfo(mPackageName,
129                mPackageInfo.applicationInfo.uid);
130
131        boolean hasAccess = mUsageState.isPermissible();
132        mSwitchPref.setChecked(hasAccess);
133        mSwitchPref.setEnabled(mUsageState.permissionDeclared);
134        mUsagePrefs.setEnabled(hasAccess);
135
136        ResolveInfo resolveInfo = mPm.resolveActivityAsUser(mSettingsIntent,
137                PackageManager.GET_META_DATA, mUserId);
138        if (resolveInfo != null) {
139            if (findPreference(KEY_APP_OPS_SETTINGS_PREFS) == null) {
140                getPreferenceScreen().addPreference(mUsagePrefs);
141            }
142            Bundle metaData = resolveInfo.activityInfo.metaData;
143            mSettingsIntent.setComponent(new ComponentName(resolveInfo.activityInfo.packageName,
144                    resolveInfo.activityInfo.name));
145            if (metaData != null
146                    && metaData.containsKey(Settings.METADATA_USAGE_ACCESS_REASON)) {
147                mSwitchPref.setSummary(
148                        metaData.getString(Settings.METADATA_USAGE_ACCESS_REASON));
149            }
150        } else {
151            if (findPreference(KEY_APP_OPS_SETTINGS_PREFS) != null) {
152                getPreferenceScreen().removePreference(mUsagePrefs);
153            }
154        }
155
156        return true;
157    }
158
159    @Override
160    protected AlertDialog createDialog(int id, int errorCode) {
161        return null;
162    }
163
164    @Override
165    public int getMetricsCategory() {
166        return MetricsEvent.APPLICATIONS_USAGE_ACCESS_DETAIL;
167    }
168
169}
170