1 /**
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations
14  * under the License.
15  */
16 
17 package com.android.settings.applications;
18 
19 import android.app.Activity;
20 import android.app.AppOpsManager;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.pm.PackageInfo;
24 import android.content.pm.PackageManager;
25 import android.content.pm.PackageManager.NameNotFoundException;
26 import android.content.pm.PermissionGroupInfo;
27 import android.content.pm.PermissionInfo;
28 import android.content.res.Resources;
29 import android.graphics.drawable.Drawable;
30 import android.os.Bundle;
31 import android.util.Log;
32 import android.view.LayoutInflater;
33 import android.view.View;
34 import android.view.ViewGroup;
35 import android.widget.CompoundButton;
36 import android.widget.ImageView;
37 import android.widget.LinearLayout;
38 import android.widget.Switch;
39 import android.widget.TextView;
40 
41 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
42 import com.android.settings.core.InstrumentedPreferenceFragment;
43 import com.android.settings.R;
44 import com.android.settings.SettingsActivity;
45 import com.android.settings.Utils;
46 
47 import java.util.List;
48 
49 public class AppOpsDetails extends InstrumentedPreferenceFragment {
50     static final String TAG = "AppOpsDetails";
51 
52     public static final String ARG_PACKAGE_NAME = "package";
53 
54     private AppOpsState mState;
55     private PackageManager mPm;
56     private AppOpsManager mAppOps;
57     private PackageInfo mPackageInfo;
58     private LayoutInflater mInflater;
59     private View mRootView;
60     private LinearLayout mOperationsSection;
61 
62     // Utility method to set application label and icon.
setAppLabelAndIcon(PackageInfo pkgInfo)63     private void setAppLabelAndIcon(PackageInfo pkgInfo) {
64         final View appSnippet = mRootView.findViewById(R.id.app_snippet);
65         CharSequence label = mPm.getApplicationLabel(pkgInfo.applicationInfo);
66         Drawable icon = mPm.getApplicationIcon(pkgInfo.applicationInfo);
67         InstalledAppDetails.setupAppSnippet(appSnippet, label, icon,
68                 pkgInfo != null ? pkgInfo.versionName : null);
69     }
70 
retrieveAppEntry()71     private String retrieveAppEntry() {
72         final Bundle args = getArguments();
73         String packageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null;
74         if (packageName == null) {
75             Intent intent = (args == null) ?
76                     getActivity().getIntent() : (Intent) args.getParcelable("intent");
77             if (intent != null) {
78                 packageName = intent.getData().getSchemeSpecificPart();
79             }
80         }
81         try {
82             mPackageInfo = mPm.getPackageInfo(packageName,
83                     PackageManager.MATCH_DISABLED_COMPONENTS |
84                     PackageManager.MATCH_ANY_USER);
85         } catch (NameNotFoundException e) {
86             Log.e(TAG, "Exception when retrieving package:" + packageName, e);
87             mPackageInfo = null;
88         }
89 
90         return packageName;
91     }
92 
refreshUi()93     private boolean refreshUi() {
94         if (mPackageInfo == null) {
95             return false;
96         }
97 
98         setAppLabelAndIcon(mPackageInfo);
99 
100         Resources res = getActivity().getResources();
101 
102         mOperationsSection.removeAllViews();
103         String lastPermGroup = "";
104         for (AppOpsState.OpsTemplate tpl : AppOpsState.ALL_TEMPLATES) {
105             List<AppOpsState.AppOpEntry> entries = mState.buildState(tpl,
106                     mPackageInfo.applicationInfo.uid, mPackageInfo.packageName);
107             for (final AppOpsState.AppOpEntry entry : entries) {
108                 final AppOpsManager.OpEntry firstOp = entry.getOpEntry(0);
109                 final View view = mInflater.inflate(R.layout.app_ops_details_item,
110                         mOperationsSection, false);
111                 mOperationsSection.addView(view);
112                 String perm = AppOpsManager.opToPermission(firstOp.getOp());
113                 if (perm != null) {
114                     try {
115                         PermissionInfo pi = mPm.getPermissionInfo(perm, 0);
116                         if (pi.group != null && !lastPermGroup.equals(pi.group)) {
117                             lastPermGroup = pi.group;
118                             PermissionGroupInfo pgi = mPm.getPermissionGroupInfo(pi.group, 0);
119                             if (pgi.icon != 0) {
120                                 ((ImageView)view.findViewById(R.id.op_icon)).setImageDrawable(
121                                         pgi.loadIcon(mPm));
122                             }
123                         }
124                     } catch (NameNotFoundException e) {
125                     }
126                 }
127                 ((TextView)view.findViewById(R.id.op_name)).setText(
128                         entry.getSwitchText(mState));
129                 ((TextView)view.findViewById(R.id.op_time)).setText(
130                         entry.getTimeText(res, true));
131                 Switch sw = (Switch)view.findViewById(R.id.switchWidget);
132                 final int switchOp = AppOpsManager.opToSwitch(firstOp.getOp());
133                 sw.setChecked(mAppOps.checkOp(switchOp, entry.getPackageOps().getUid(),
134                         entry.getPackageOps().getPackageName()) == AppOpsManager.MODE_ALLOWED);
135                 sw.setOnCheckedChangeListener(new Switch.OnCheckedChangeListener() {
136                     @Override
137                     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
138                         mAppOps.setMode(switchOp, entry.getPackageOps().getUid(),
139                                 entry.getPackageOps().getPackageName(), isChecked
140                                 ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
141                     }
142                 });
143             }
144         }
145 
146         return true;
147     }
148 
setIntentAndFinish(boolean finish, boolean appChanged)149     private void setIntentAndFinish(boolean finish, boolean appChanged) {
150         Intent intent = new Intent();
151         intent.putExtra(ManageApplications.APP_CHG, appChanged);
152         SettingsActivity sa = (SettingsActivity)getActivity();
153         sa.finishPreferencePanel(this, Activity.RESULT_OK, intent);
154     }
155 
156     /** Called when the activity is first created. */
157     @Override
onCreate(Bundle icicle)158     public void onCreate(Bundle icicle) {
159         super.onCreate(icicle);
160 
161         mState = new AppOpsState(getActivity());
162         mPm = getActivity().getPackageManager();
163         mInflater = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
164         mAppOps = (AppOpsManager)getActivity().getSystemService(Context.APP_OPS_SERVICE);
165 
166         retrieveAppEntry();
167 
168         setHasOptionsMenu(true);
169     }
170 
171     @Override
onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)172     public View onCreateView(
173             LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
174         final View view = inflater.inflate(R.layout.app_ops_details, container, false);
175         Utils.prepareCustomPreferencesList(container, view, view, false);
176 
177         mRootView = view;
178         mOperationsSection = (LinearLayout)view.findViewById(R.id.operations_section);
179         return view;
180     }
181 
182     @Override
getMetricsCategory()183     public int getMetricsCategory() {
184         return MetricsEvent.APP_OPS_DETAILS;
185     }
186 
187     @Override
onResume()188     public void onResume() {
189         super.onResume();
190         if (!refreshUi()) {
191             setIntentAndFinish(true, true);
192         }
193     }
194 }
195