| /* |
| * Copyright (C) 2020 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.INotificationManager; |
| import android.app.NotificationChannel; |
| import android.app.NotificationChannelGroup; |
| import android.content.Context; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.PackageManager; |
| import android.graphics.drawable.Drawable; |
| import android.os.RemoteException; |
| import android.service.notification.StatusBarNotification; |
| import android.text.TextUtils; |
| 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.annotations.VisibleForTesting; |
| import com.android.systemui.R; |
| import com.android.systemui.statusbar.notification.collection.NotificationEntry; |
| |
| import java.util.Set; |
| |
| /** |
| * The guts of a conversation notification that doesn't use valid shortcuts that is revealed when |
| * performing a long press. |
| */ |
| public class PartialConversationInfo extends LinearLayout implements |
| NotificationGuts.GutsContent { |
| private static final String TAG = "PartialConvoGuts"; |
| |
| private INotificationManager mINotificationManager; |
| private PackageManager mPm; |
| private String mPackageName; |
| private String mAppName; |
| private int mAppUid; |
| private String mDelegatePkg; |
| private NotificationChannel mNotificationChannel; |
| private StatusBarNotification mSbn; |
| private boolean mIsDeviceProvisioned; |
| private boolean mIsNonBlockable; |
| private Set<NotificationChannel> mUniqueChannelsInRow; |
| private Drawable mPkgIcon; |
| |
| private boolean mPresentingChannelEditorDialog = false; |
| |
| private NotificationInfo.OnSettingsClickListener mOnSettingsClickListener; |
| private NotificationGuts mGutsContainer; |
| private ChannelEditorDialogController mChannelEditorDialogController; |
| |
| @VisibleForTesting |
| boolean mSkipPost = false; |
| |
| private OnClickListener mOnDone = v -> { |
| mGutsContainer.closeControls(v, /* save= */ false); |
| }; |
| |
| public PartialConversationInfo(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| } |
| |
| public void bindNotification( |
| PackageManager pm, |
| INotificationManager iNotificationManager, |
| ChannelEditorDialogController channelEditorDialogController, |
| String pkg, |
| NotificationChannel notificationChannel, |
| Set<NotificationChannel> uniqueChannelsInRow, |
| NotificationEntry entry, |
| NotificationInfo.OnSettingsClickListener onSettingsClick, |
| boolean isDeviceProvisioned, |
| boolean isNonBlockable) { |
| mINotificationManager = iNotificationManager; |
| mPackageName = pkg; |
| mSbn = entry.getSbn(); |
| mPm = pm; |
| mAppName = mPackageName; |
| mOnSettingsClickListener = onSettingsClick; |
| mNotificationChannel = notificationChannel; |
| mAppUid = mSbn.getUid(); |
| mDelegatePkg = mSbn.getOpPkg(); |
| mIsDeviceProvisioned = isDeviceProvisioned; |
| mIsNonBlockable = isNonBlockable; |
| mChannelEditorDialogController = channelEditorDialogController; |
| mUniqueChannelsInRow = uniqueChannelsInRow; |
| |
| bindHeader(); |
| bindActions(); |
| |
| View turnOffButton = findViewById(R.id.turn_off_notifications); |
| turnOffButton.setOnClickListener(getTurnOffNotificationsClickListener()); |
| turnOffButton.setVisibility(turnOffButton.hasOnClickListeners() && !mIsNonBlockable |
| ? VISIBLE : GONE); |
| |
| View done = findViewById(R.id.done); |
| done.setOnClickListener(mOnDone); |
| done.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate()); |
| } |
| |
| private void bindActions() { |
| final OnClickListener settingsOnClickListener = getSettingsOnClickListener(); |
| final View settingsButton = findViewById(R.id.info); |
| settingsButton.setOnClickListener(settingsOnClickListener); |
| settingsButton.setVisibility(settingsButton.hasOnClickListeners() ? VISIBLE : GONE); |
| |
| findViewById(R.id.settings_link).setOnClickListener(settingsOnClickListener); |
| |
| TextView msg = findViewById(R.id.non_configurable_text); |
| msg.setText(getResources().getString(R.string.no_shortcut, mAppName)); |
| } |
| |
| private void bindHeader() { |
| bindPackage(); |
| // Delegate |
| bindDelegate(); |
| } |
| |
| private OnClickListener getSettingsOnClickListener() { |
| if (mAppUid >= 0 && mOnSettingsClickListener != null && mIsDeviceProvisioned) { |
| final int appUidF = mAppUid; |
| return ((View view) -> { |
| mOnSettingsClickListener.onClick(view, mNotificationChannel, appUidF); |
| }); |
| } |
| return null; |
| } |
| |
| private OnClickListener getTurnOffNotificationsClickListener() { |
| return ((View view) -> { |
| if (!mPresentingChannelEditorDialog && mChannelEditorDialogController != null) { |
| mPresentingChannelEditorDialog = true; |
| |
| mChannelEditorDialogController.prepareDialogForApp(mAppName, mPackageName, mAppUid, |
| mUniqueChannelsInRow, mPkgIcon, mOnSettingsClickListener); |
| mChannelEditorDialogController.setOnFinishListener(() -> { |
| mPresentingChannelEditorDialog = false; |
| mGutsContainer.closeControls(this, false); |
| }); |
| mChannelEditorDialogController.show(); |
| } |
| }); |
| } |
| |
| private void bindPackage() { |
| ApplicationInfo info; |
| try { |
| info = mPm.getApplicationInfo( |
| mPackageName, |
| PackageManager.MATCH_UNINSTALLED_PACKAGES |
| | PackageManager.MATCH_DISABLED_COMPONENTS |
| | PackageManager.MATCH_DIRECT_BOOT_UNAWARE |
| | PackageManager.MATCH_DIRECT_BOOT_AWARE); |
| if (info != null) { |
| mAppName = String.valueOf(mPm.getApplicationLabel(info)); |
| mPkgIcon = mPm.getApplicationIcon(info); |
| } |
| } catch (PackageManager.NameNotFoundException e) { |
| mPkgIcon = mPm.getDefaultActivityIcon(); |
| } |
| TextView name = findViewById(R.id.name); |
| name.setText(mAppName); |
| ImageView image = findViewById(R.id.icon); |
| image.setImageDrawable(mPkgIcon); |
| } |
| |
| private void bindDelegate() { |
| TextView delegateView = findViewById(R.id.delegate_name); |
| |
| if (!TextUtils.equals(mPackageName, mDelegatePkg)) { |
| // this notification was posted by a delegate! |
| delegateView.setVisibility(View.VISIBLE); |
| } else { |
| delegateView.setVisibility(View.GONE); |
| } |
| } |
| |
| private void bindGroup() { |
| // Set group information if this channel has an associated group. |
| CharSequence groupName = null; |
| if (mNotificationChannel != null && mNotificationChannel.getGroup() != null) { |
| try { |
| final NotificationChannelGroup notificationChannelGroup = |
| mINotificationManager.getNotificationChannelGroupForPackage( |
| mNotificationChannel.getGroup(), mPackageName, mAppUid); |
| if (notificationChannelGroup != null) { |
| groupName = notificationChannelGroup.getName(); |
| } |
| } catch (RemoteException e) { |
| } |
| } |
| TextView groupNameView = findViewById(R.id.group_name); |
| if (groupName != null) { |
| groupNameView.setText(groupName); |
| groupNameView.setVisibility(VISIBLE); |
| } else { |
| groupNameView.setVisibility(GONE); |
| } |
| } |
| |
| @Override |
| public boolean post(Runnable action) { |
| if (mSkipPost) { |
| action.run(); |
| return true; |
| } else { |
| return super.post(action); |
| } |
| } |
| |
| @Override |
| protected void onFinishInflate() { |
| super.onFinishInflate(); |
| } |
| |
| @Override |
| public void onFinishedClosing() { |
| // TODO: do we need to do anything here? |
| } |
| |
| @Override |
| public boolean needsFalsingProtection() { |
| return true; |
| } |
| |
| @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)); |
| } |
| } |
| } |
| |
| @Override |
| public void setGutsParent(NotificationGuts guts) { |
| mGutsContainer = guts; |
| } |
| |
| @Override |
| public boolean willBeRemoved() { |
| return false; |
| } |
| |
| @Override |
| public boolean shouldBeSavedOnClose() { |
| return false; |
| } |
| |
| @Override |
| public View getContentView() { |
| return this; |
| } |
| |
| @Override |
| public boolean handleCloseControls(boolean save, boolean force) { |
| return false; |
| } |
| |
| @Override |
| public int getActualHeight() { |
| return getHeight(); |
| } |
| |
| @VisibleForTesting |
| public boolean isAnimating() { |
| return false; |
| } |
| } |