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
17package com.android.settings.applications;
18
19import android.app.Activity;
20import android.app.AppOpsManager;
21import android.content.Context;
22import android.content.Intent;
23import android.content.pm.PackageInfo;
24import android.content.pm.PackageManager;
25import android.content.pm.PackageManager.NameNotFoundException;
26import android.content.pm.PermissionGroupInfo;
27import android.content.pm.PermissionInfo;
28import android.content.res.Resources;
29import android.graphics.drawable.Drawable;
30import android.os.Bundle;
31import android.util.Log;
32import android.view.LayoutInflater;
33import android.view.View;
34import android.view.ViewGroup;
35import android.widget.CompoundButton;
36import android.widget.ImageView;
37import android.widget.LinearLayout;
38import android.widget.Switch;
39import android.widget.TextView;
40
41import com.android.internal.logging.MetricsProto.MetricsEvent;
42import com.android.settings.InstrumentedFragment;
43import com.android.settings.R;
44import com.android.settings.SettingsActivity;
45import com.android.settings.Utils;
46
47import java.util.List;
48
49public class AppOpsDetails extends InstrumentedFragment {
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.
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
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.GET_DISABLED_COMPONENTS |
84                    PackageManager.GET_UNINSTALLED_PACKAGES);
85        } catch (NameNotFoundException e) {
86            Log.e(TAG, "Exception when retrieving package:" + packageName, e);
87            mPackageInfo = null;
88        }
89
90        return packageName;
91    }
92
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
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
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
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
183    protected int getMetricsCategory() {
184        return MetricsEvent.APP_OPS_DETAILS;
185    }
186
187    @Override
188    public void onResume() {
189        super.onResume();
190        if (!refreshUi()) {
191            setIntentAndFinish(true, true);
192        }
193    }
194}
195