blob: cfc4da4e4898c3277d9d077248fa2c12b11583ce [file] [log] [blame]
Julia Reynoldsb5867452018-02-28 16:31:35 -05001/*
2 * Copyright (C) 2018 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.systemui.statusbar;
18
19import android.app.AppOpsManager;
20import android.content.Context;
21import android.content.pm.ApplicationInfo;
22import android.content.pm.PackageInfo;
23import android.content.pm.PackageManager;
24import android.graphics.drawable.Drawable;
25import android.os.RemoteException;
26import android.service.notification.StatusBarNotification;
27import android.util.ArraySet;
28import android.util.AttributeSet;
29import android.view.View;
30import android.view.accessibility.AccessibilityEvent;
31import android.widget.ImageView;
32import android.widget.LinearLayout;
33import android.widget.TextView;
34
35import com.android.internal.logging.MetricsLogger;
36import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
37import com.android.systemui.R;
38
39/**
40 * The guts of a notification revealed when performing a long press.
41 */
42public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsContent {
43 private static final String TAG = "AppOpsGuts";
44
45 private PackageManager mPm;
46
47 private String mPkg;
48 private String mAppName;
49 private int mAppUid;
50 private StatusBarNotification mSbn;
51 private ArraySet<Integer> mAppOps;
52 private MetricsLogger mMetricsLogger;
53 private OnSettingsClickListener mOnSettingsClickListener;
54 private NotificationGuts mGutsContainer;
55
56 private OnClickListener mOnOk = v -> {
57 closeControls(v);
58 };
59
60 public AppOpsInfo(Context context, AttributeSet attrs) {
61 super(context, attrs);
62 }
63
64 public interface OnSettingsClickListener {
65 void onClick(View v, String pkg, int uid, ArraySet<Integer> ops);
66 }
67
68 public void bindGuts(final PackageManager pm,
69 final OnSettingsClickListener onSettingsClick,
70 final StatusBarNotification sbn,
71 ArraySet<Integer> activeOps) {
72 mPkg = sbn.getPackageName();
73 mSbn = sbn;
74 mPm = pm;
75 mAppName = mPkg;
76 mOnSettingsClickListener = onSettingsClick;
77 mAppOps = activeOps;
78
79 bindHeader();
80 bindPrompt();
81 bindButtons();
82
83 mMetricsLogger = new MetricsLogger();
84 mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, true);
85 }
86
87 private void bindHeader() {
88 // Package name
89 Drawable pkgicon = null;
90 ApplicationInfo info;
91 try {
92 info = mPm.getApplicationInfo(mPkg,
93 PackageManager.MATCH_UNINSTALLED_PACKAGES
94 | PackageManager.MATCH_DISABLED_COMPONENTS
95 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
96 | PackageManager.MATCH_DIRECT_BOOT_AWARE);
97 if (info != null) {
98 mAppUid = mSbn.getUid();
99 mAppName = String.valueOf(mPm.getApplicationLabel(info));
100 pkgicon = mPm.getApplicationIcon(info);
101 }
102 } catch (PackageManager.NameNotFoundException e) {
103 // app is gone, just show package name and generic icon
104 pkgicon = mPm.getDefaultActivityIcon();
105 }
106 ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
107 ((TextView) findViewById(R.id.pkgname)).setText(mAppName);
108 }
109
110 private void bindPrompt() {
111 final TextView prompt = findViewById(R.id.prompt);
Julia Reynolds15db7cd2018-05-07 09:42:38 -0400112 prompt.setText(getPrompt());
Julia Reynoldsb5867452018-02-28 16:31:35 -0500113 }
114
115 private void bindButtons() {
116 View settings = findViewById(R.id.settings);
117 settings.setOnClickListener((View view) -> {
118 mOnSettingsClickListener.onClick(view, mPkg, mAppUid, mAppOps);
119 });
120 TextView ok = findViewById(R.id.ok);
121 ok.setOnClickListener(mOnOk);
122 }
123
Julia Reynolds15db7cd2018-05-07 09:42:38 -0400124 private String getPrompt() {
125 if (mAppOps == null || mAppOps.size() == 0) {
126 return "";
127 } else if (mAppOps.size() == 1) {
128 if (mAppOps.contains(AppOpsManager.OP_CAMERA)) {
129 return mContext.getString(R.string.appops_camera);
130 } else if (mAppOps.contains(AppOpsManager.OP_RECORD_AUDIO)) {
131 return mContext.getString(R.string.appops_microphone);
Julia Reynoldsb5867452018-02-28 16:31:35 -0500132 } else {
Julia Reynolds15db7cd2018-05-07 09:42:38 -0400133 return mContext.getString(R.string.appops_overlay);
134 }
135 } else if (mAppOps.size() == 2) {
136 if (mAppOps.contains(AppOpsManager.OP_CAMERA)) {
137 if (mAppOps.contains(AppOpsManager.OP_RECORD_AUDIO)) {
138 return mContext.getString(R.string.appops_camera_mic);
139 } else {
140 return mContext.getString(R.string.appops_camera_overlay);
141 }
142 } else {
143 return mContext.getString(R.string.appops_mic_overlay);
Julia Reynoldsb5867452018-02-28 16:31:35 -0500144 }
145 } else {
Julia Reynolds15db7cd2018-05-07 09:42:38 -0400146 return mContext.getString(R.string.appops_camera_mic_overlay);
Julia Reynoldsb5867452018-02-28 16:31:35 -0500147 }
Julia Reynoldsb5867452018-02-28 16:31:35 -0500148 }
149
150 @Override
151 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
152 super.onInitializeAccessibilityEvent(event);
153 if (mGutsContainer != null &&
154 event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
155 if (mGutsContainer.isExposed()) {
156 event.getText().add(mContext.getString(
157 R.string.notification_channel_controls_opened_accessibility, mAppName));
158 } else {
159 event.getText().add(mContext.getString(
160 R.string.notification_channel_controls_closed_accessibility, mAppName));
161 }
162 }
163 }
164
165 private void closeControls(View v) {
166 mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false);
167 int[] parentLoc = new int[2];
168 int[] targetLoc = new int[2];
169 mGutsContainer.getLocationOnScreen(parentLoc);
170 v.getLocationOnScreen(targetLoc);
171 final int centerX = v.getWidth() / 2;
172 final int centerY = v.getHeight() / 2;
173 final int x = targetLoc[0] - parentLoc[0] + centerX;
174 final int y = targetLoc[1] - parentLoc[1] + centerY;
175 mGutsContainer.closeControls(x, y, false, false);
176 }
177
178 @Override
179 public void setGutsParent(NotificationGuts guts) {
180 mGutsContainer = guts;
181 }
182
183 @Override
184 public boolean willBeRemoved() {
185 return false;
186 }
187
188 @Override
189 public View getContentView() {
190 return this;
191 }
192
193 @Override
194 public boolean handleCloseControls(boolean save, boolean force) {
195 return false;
196 }
197
198 @Override
199 public int getActualHeight() {
200 return getHeight();
201 }
202}