blob: 10fc990e2c5b242b790ac63aa2c50e2f9f4266ed [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.statusbar.notification.row;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
/**
* The guts of a notification revealed when performing a long press.
*/
public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsContent {
private static final String TAG = "AppOpsGuts";
private PackageManager mPm;
private String mPkg;
private String mAppName;
private int mAppUid;
private StatusBarNotification mSbn;
private ArraySet<Integer> mAppOps;
private MetricsLogger mMetricsLogger;
private OnSettingsClickListener mOnSettingsClickListener;
private NotificationGuts mGutsContainer;
private OnClickListener mOnOk = v -> {
closeControls(v);
};
public AppOpsInfo(Context context, AttributeSet attrs) {
super(context, attrs);
}
public interface OnSettingsClickListener {
void onClick(View v, String pkg, int uid, ArraySet<Integer> ops);
}
public void bindGuts(final PackageManager pm,
final OnSettingsClickListener onSettingsClick,
final StatusBarNotification sbn,
ArraySet<Integer> activeOps) {
mPkg = sbn.getPackageName();
mSbn = sbn;
mPm = pm;
mAppName = mPkg;
mOnSettingsClickListener = onSettingsClick;
mAppOps = activeOps;
bindHeader();
bindPrompt();
bindButtons();
mMetricsLogger = new MetricsLogger();
mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, true);
}
private void bindHeader() {
// Package name
Drawable pkgicon = null;
ApplicationInfo info;
try {
info = mPm.getApplicationInfo(mPkg,
PackageManager.MATCH_UNINSTALLED_PACKAGES
| PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_DIRECT_BOOT_AWARE);
if (info != null) {
mAppUid = mSbn.getUid();
mAppName = String.valueOf(mPm.getApplicationLabel(info));
pkgicon = mPm.getApplicationIcon(info);
}
} catch (PackageManager.NameNotFoundException e) {
// app is gone, just show package name and generic icon
pkgicon = mPm.getDefaultActivityIcon();
}
((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
((TextView) findViewById(R.id.pkgname)).setText(mAppName);
}
private void bindPrompt() {
final TextView prompt = findViewById(R.id.prompt);
prompt.setText(getPrompt());
}
private void bindButtons() {
View settings = findViewById(R.id.settings);
settings.setOnClickListener((View view) -> {
mOnSettingsClickListener.onClick(view, mPkg, mAppUid, mAppOps);
});
TextView ok = findViewById(R.id.ok);
ok.setOnClickListener(mOnOk);
}
private String getPrompt() {
if (mAppOps == null || mAppOps.size() == 0) {
return "";
} else if (mAppOps.size() == 1) {
if (mAppOps.contains(AppOpsManager.OP_CAMERA)) {
return mContext.getString(R.string.appops_camera);
} else if (mAppOps.contains(AppOpsManager.OP_RECORD_AUDIO)) {
return mContext.getString(R.string.appops_microphone);
} else {
return mContext.getString(R.string.appops_overlay);
}
} else if (mAppOps.size() == 2) {
if (mAppOps.contains(AppOpsManager.OP_CAMERA)) {
if (mAppOps.contains(AppOpsManager.OP_RECORD_AUDIO)) {
return mContext.getString(R.string.appops_camera_mic);
} else {
return mContext.getString(R.string.appops_camera_overlay);
}
} else {
return mContext.getString(R.string.appops_mic_overlay);
}
} else {
return mContext.getString(R.string.appops_camera_mic_overlay);
}
}
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
if (mGutsContainer != null &&
event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
if (mGutsContainer.isExposed()) {
event.getText().add(mContext.getString(
R.string.notification_channel_controls_opened_accessibility, mAppName));
} else {
event.getText().add(mContext.getString(
R.string.notification_channel_controls_closed_accessibility, mAppName));
}
}
}
private void closeControls(View v) {
mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false);
int[] parentLoc = new int[2];
int[] targetLoc = new int[2];
mGutsContainer.getLocationOnScreen(parentLoc);
v.getLocationOnScreen(targetLoc);
final int centerX = v.getWidth() / 2;
final int centerY = v.getHeight() / 2;
final int x = targetLoc[0] - parentLoc[0] + centerX;
final int y = targetLoc[1] - parentLoc[1] + centerY;
mGutsContainer.closeControls(x, y, false, false);
}
@Override
public void setGutsParent(NotificationGuts guts) {
mGutsContainer = guts;
}
@Override
public boolean willBeRemoved() {
return false;
}
@Override
public boolean shouldBeSaved() {
return false;
}
@Override
public View getContentView() {
return this;
}
@Override
public boolean handleCloseControls(boolean save, boolean force) {
return false;
}
@Override
public int getActualHeight() {
return getHeight();
}
}