• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.systemui.statusbar;
18 
19 import android.app.AppOpsManager;
20 import android.content.Context;
21 import android.content.pm.ApplicationInfo;
22 import android.content.pm.PackageInfo;
23 import android.content.pm.PackageManager;
24 import android.graphics.drawable.Drawable;
25 import android.os.RemoteException;
26 import android.service.notification.StatusBarNotification;
27 import android.util.ArraySet;
28 import android.util.AttributeSet;
29 import android.view.View;
30 import android.view.accessibility.AccessibilityEvent;
31 import android.widget.ImageView;
32 import android.widget.LinearLayout;
33 import android.widget.TextView;
34 
35 import com.android.internal.logging.MetricsLogger;
36 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
37 import com.android.systemui.R;
38 
39 /**
40  * The guts of a notification revealed when performing a long press.
41  */
42 public 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 
AppOpsInfo(Context context, AttributeSet attrs)60     public AppOpsInfo(Context context, AttributeSet attrs) {
61         super(context, attrs);
62     }
63 
64     public interface OnSettingsClickListener {
onClick(View v, String pkg, int uid, ArraySet<Integer> ops)65         void onClick(View v, String pkg, int uid, ArraySet<Integer> ops);
66     }
67 
bindGuts(final PackageManager pm, final OnSettingsClickListener onSettingsClick, final StatusBarNotification sbn, ArraySet<Integer> activeOps)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 
bindHeader()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 
bindPrompt()110     private void bindPrompt() {
111         final TextView prompt = findViewById(R.id.prompt);
112         prompt.setText(getPrompt());
113     }
114 
bindButtons()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 
getPrompt()124     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);
132             } else {
133                 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);
144             }
145         } else {
146             return mContext.getString(R.string.appops_camera_mic_overlay);
147         }
148     }
149 
150     @Override
onInitializeAccessibilityEvent(AccessibilityEvent event)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 
closeControls(View v)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
setGutsParent(NotificationGuts guts)179     public void setGutsParent(NotificationGuts guts) {
180         mGutsContainer = guts;
181     }
182 
183     @Override
willBeRemoved()184     public boolean willBeRemoved() {
185         return false;
186     }
187 
188     @Override
shouldBeSaved()189     public boolean shouldBeSaved() {
190         return false;
191     }
192 
193     @Override
getContentView()194     public View getContentView() {
195         return this;
196     }
197 
198     @Override
handleCloseControls(boolean save, boolean force)199     public boolean handleCloseControls(boolean save, boolean force) {
200         return false;
201     }
202 
203     @Override
getActualHeight()204     public int getActualHeight() {
205         return getHeight();
206     }
207 }
208