AppPermissionsFragmentWear.java revision f9bf4f795615bac03d1b35a0138318473b1ef6bf
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*/
16
17package com.android.packageinstaller.permission.ui.wear;
18
19import android.Manifest;
20import android.app.Activity;
21import android.app.Fragment;
22import android.content.Intent;
23import android.content.pm.PackageInfo;
24import android.content.pm.PackageManager;
25import android.os.Bundle;
26import android.support.wearable.view.WearableListView;
27import android.util.Log;
28import android.view.LayoutInflater;
29import android.view.View;
30import android.view.ViewGroup;
31import android.widget.Toast;
32
33import com.android.packageinstaller.R;
34import com.android.packageinstaller.permission.model.AppPermissionGroup;
35import com.android.packageinstaller.permission.model.AppPermissions;
36import com.android.packageinstaller.permission.ui.wear.settings.PermissionsSettingsAdapter;
37import com.android.packageinstaller.permission.ui.wear.settings.SettingsAdapter;
38import com.android.packageinstaller.permission.utils.LocationUtils;
39import com.android.packageinstaller.permission.utils.SafetyNetLogger;
40import com.android.packageinstaller.permission.utils.Utils;
41
42import java.util.ArrayList;
43import java.util.List;
44
45public final class AppPermissionsFragmentWear extends TitledSettingsFragment {
46
47    private static final String LOG_TAG = "ManagePermsFragment";
48
49    private static final int WARNING_CONFIRMATION_REQUEST = 252;
50    private List<AppPermissionGroup> mToggledGroups;
51    private AppPermissions mAppPermissions;
52    private PermissionsSettingsAdapter mAdapter;
53
54    private boolean mHasConfirmedRevoke;
55
56    public static AppPermissionsFragmentWear newInstance(String packageName) {
57        return setPackageName(new AppPermissionsFragmentWear(), packageName);
58    }
59
60    private static <T extends Fragment> T setPackageName(T fragment, String packageName) {
61        Bundle arguments = new Bundle();
62        arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
63        fragment.setArguments(arguments);
64        return fragment;
65    }
66
67    @Override
68    public void onCreate(Bundle savedInstanceState) {
69        super.onCreate(savedInstanceState);
70
71        String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
72        Activity activity = getActivity();
73        PackageManager pm = activity.getPackageManager();
74        PackageInfo packageInfo;
75
76        try {
77            packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
78        } catch (PackageManager.NameNotFoundException e) {
79            Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e);
80            packageInfo = null;
81        }
82
83        if (packageInfo == null) {
84            Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show();
85            activity.finish();
86            return;
87        }
88
89        mAppPermissions = new AppPermissions(activity, packageInfo, null, true, new Runnable() {
90            @Override
91            public void run() {
92                getActivity().finish();
93            }
94        });
95
96        mAdapter = new PermissionsSettingsAdapter(getContext());
97
98        initializePermissionGroupList();
99    }
100
101    @Override
102    public View onCreateView(LayoutInflater inflater, ViewGroup container,
103            Bundle savedInstanceState) {
104        return inflater.inflate(R.layout.settings, container, false);
105    }
106
107    @Override
108    public void onResume() {
109        super.onResume();
110        mAppPermissions.refresh();
111
112        // Also refresh the UI
113        final int count = mAdapter.getItemCount();
114        for (int i = 0; i < count; ++i) {
115            updatePermissionGroupSetting(i);
116        }
117    }
118
119    @Override
120    public void onViewCreated(View view, Bundle savedInstanceState) {
121        super.onViewCreated(view, savedInstanceState);
122        if (mAppPermissions != null) {
123            initializeLayout(mAdapter);
124            mHeader.setText(R.string.app_permissions);
125            mDetails.setText(R.string.no_permissions);
126            if (mAdapter.getItemCount() == 0) {
127                mDetails.setVisibility(View.VISIBLE);
128                mWheel.setVisibility(View.GONE);
129            } else {
130                mDetails.setVisibility(View.GONE);
131                mWheel.setVisibility(View.VISIBLE);
132            }
133        }
134    }
135
136    private void initializePermissionGroupList() {
137        final String packageName = mAppPermissions.getPackageInfo().packageName;
138        List<AppPermissionGroup> groups = mAppPermissions.getPermissionGroups();
139        List<SettingsAdapter.Setting<AppPermissionGroup>> nonSystemGroups = new ArrayList<>();
140
141        final int count = groups.size();
142        for (int i = 0; i < count; ++i) {
143            final AppPermissionGroup group = groups.get(i);
144            if (!Utils.shouldShowPermission(group, packageName)) {
145                continue;
146            }
147
148            boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG);
149
150            SettingsAdapter.Setting<AppPermissionGroup> setting =
151                    new SettingsAdapter.Setting<AppPermissionGroup>(
152                            group.getLabel(),
153                            getPermissionGroupIcon(group),
154                            i);
155            setting.data = group;
156
157            // The UI shows System settings first, then non-system settings
158            if (isPlatform) {
159                mAdapter.addSetting(setting);
160            } else {
161                nonSystemGroups.add(setting);
162            }
163        }
164
165        // Now add the non-system settings to the end of the list
166        final int nonSystemCount = nonSystemGroups.size();
167        for (int i = 0; i < nonSystemCount; ++i) {
168            final SettingsAdapter.Setting<AppPermissionGroup> setting = nonSystemGroups.get(i);
169            mAdapter.addSetting(setting);
170        }
171    }
172
173    @Override
174    public void onPause() {
175        super.onPause();
176        logAndClearToggledGroups();
177    }
178
179    @Override
180    public void onClick(WearableListView.ViewHolder view) {
181        final int index = view.getPosition();
182        SettingsAdapter.Setting<AppPermissionGroup> setting = mAdapter.get(index);
183        final AppPermissionGroup group = setting.data;
184
185        if (group == null) {
186            Log.e(LOG_TAG, "Error: AppPermissionGroup is null");
187            return;
188        }
189
190        // The way WearableListView is designed, there is no way to avoid this click handler
191        // Since the policy is fixed, ignore the click as the user is not able to change the state
192        // of this permission group
193        if (group.isPolicyFixed()) {
194            return;
195        }
196
197        addToggledGroup(group);
198
199        if (LocationUtils.isLocationGroupAndProvider(group.getName(), group.getApp().packageName)) {
200            LocationUtils.showLocationDialog(getContext(), mAppPermissions.getAppLabel());
201            return;
202        }
203
204        if (!group.areRuntimePermissionsGranted()) {
205            group.grantRuntimePermissions(false);
206        } else {
207            final boolean grantedByDefault = group.hasGrantedByDefaultPermission();
208            if (grantedByDefault || (!group.hasRuntimePermission() && !mHasConfirmedRevoke)) {
209                Intent intent = new Intent(getActivity(), WarningConfirmationActivity.class);
210                intent.putExtra(WarningConfirmationActivity.EXTRA_WARNING_MESSAGE,
211                        getString(grantedByDefault ?
212                                R.string.system_warning : R.string.old_sdk_deny_warning));
213                intent.putExtra(WarningConfirmationActivity.EXTRA_INDEX, index);
214                startActivityForResult(intent, WARNING_CONFIRMATION_REQUEST);
215            } else {
216                group.revokeRuntimePermissions(false);
217            }
218        }
219
220        updatePermissionGroupSetting(index);
221    }
222
223    @Override
224    public void onActivityResult(int requestCode, int resultCode, Intent data) {
225        if (requestCode == WARNING_CONFIRMATION_REQUEST) {
226            if (resultCode == Activity.RESULT_OK) {
227                int index = data.getIntExtra(WarningConfirmationActivity.EXTRA_INDEX, -1);
228                if (index == -1) {
229                    Log.e(LOG_TAG, "Warning confirmation request came back with no index.");
230                    return;
231                }
232
233                SettingsAdapter.Setting<AppPermissionGroup> setting = mAdapter.get(index);
234                final AppPermissionGroup group = setting.data;
235                group.revokeRuntimePermissions(false);
236                if (!group.hasGrantedByDefaultPermission()) {
237                    mHasConfirmedRevoke = true;
238                }
239
240                updatePermissionGroupSetting(index);
241            }
242        } else {
243            super.onActivityResult(requestCode, resultCode, data);
244        }
245    }
246
247    private void updatePermissionGroupSetting(int index) {
248        SettingsAdapter.Setting<AppPermissionGroup> setting = mAdapter.get(index);
249        AppPermissionGroup group = setting.data;
250        mAdapter.updateSetting(
251                index,
252                group.getLabel(),
253                getPermissionGroupIcon(group),
254                group);
255    }
256
257    private void addToggledGroup(AppPermissionGroup group) {
258        if (mToggledGroups == null) {
259            mToggledGroups = new ArrayList<>();
260        }
261        // Double toggle is back to initial state.
262        if (mToggledGroups.contains(group)) {
263            mToggledGroups.remove(group);
264        } else {
265            mToggledGroups.add(group);
266        }
267    }
268
269    private void logAndClearToggledGroups() {
270        if (mToggledGroups != null) {
271            String packageName = mAppPermissions.getPackageInfo().packageName;
272            SafetyNetLogger.logPermissionsToggled(packageName, mToggledGroups);
273            mToggledGroups = null;
274        }
275    }
276
277    private int getPermissionGroupIcon(AppPermissionGroup group) {
278        String groupName = group.getName();
279        boolean isEnabled = group.areRuntimePermissionsGranted();
280        int resId;
281
282        switch (groupName) {
283            case Manifest.permission_group.CALENDAR:
284                resId = isEnabled ? R.drawable.ic_permission_calendar
285                        : R.drawable.ic_permission_calendardisable;
286                break;
287            case Manifest.permission_group.CAMERA:
288                resId = isEnabled ? R.drawable.ic_permission_camera
289                        : R.drawable.ic_permission_cameradisable;
290                break;
291            case Manifest.permission_group.CONTACTS:
292                resId = isEnabled ? R.drawable.ic_permission_contact
293                        : R.drawable.ic_permission_contactdisable;
294                break;
295            case Manifest.permission_group.LOCATION:
296                resId = isEnabled ? R.drawable.ic_permission_location
297                        : R.drawable.ic_permission_locationdisable;
298                break;
299            case Manifest.permission_group.MICROPHONE:
300                resId = isEnabled ? R.drawable.ic_permission_mic
301                        : R.drawable.ic_permission_micdisable;
302                break;
303            case Manifest.permission_group.PHONE:
304                resId = isEnabled ? R.drawable.ic_permission_call
305                        : R.drawable.ic_permission_calldisable;
306                break;
307            case Manifest.permission_group.SENSORS:
308                resId = isEnabled ? R.drawable.ic_permission_sensor
309                        : R.drawable.ic_permission_sensordisable;
310                break;
311            case Manifest.permission_group.SMS:
312                resId = isEnabled ? R.drawable.ic_permission_sms
313                        : R.drawable.ic_permission_smsdisable;
314                break;
315            case Manifest.permission_group.STORAGE:
316                resId = isEnabled ? R.drawable.ic_permission_storage
317                        : R.drawable.ic_permission_storagedisable;
318                break;
319            default:
320                resId = isEnabled ? R.drawable.ic_permission_shield
321                        : R.drawable.ic_permission_shielddisable;
322        }
323
324        return resId;
325    }
326}
327