Inline noti blocking is now in the form of a question

And has an 'undo' flow that matches snoozing.

Test: runtest systemui
Bug: 63927402
Change-Id: Idc17b8d950bc3da7ec9fe035dc8a65146d12c456
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 8d1bb5f..6279fdc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -18,6 +18,10 @@
 
 import static android.app.NotificationManager.IMPORTANCE_NONE;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
 import android.app.INotificationManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
@@ -38,12 +42,12 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.Switch;
 import android.widget.TextView;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.Utils;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 
 import java.lang.IllegalArgumentException;
@@ -57,25 +61,37 @@
     private static final String TAG = "InfoGuts";
 
     private INotificationManager mINotificationManager;
+    private PackageManager mPm;
+
     private String mPkg;
     private String mAppName;
     private int mAppUid;
-    private List<NotificationChannel> mNotificationChannels;
+    private int mNumNotificationChannels;
     private NotificationChannel mSingleNotificationChannel;
-    private boolean mIsSingleDefaultChannel;
-    private StatusBarNotification mSbn;
     private int mStartingUserImportance;
+    private int mChosenImportance;
+    private boolean mIsSingleDefaultChannel;
+    private boolean mNonblockable;
+    private StatusBarNotification mSbn;
+    private AnimatorSet mExpandAnimation;
 
-    private TextView mNumChannelsView;
-    private View mChannelDisabledView;
-    private TextView mSettingsLinkView;
-    private Switch mChannelEnabledSwitch;
     private CheckSaveListener mCheckSaveListener;
+    private OnSettingsClickListener mOnSettingsClickListener;
     private OnAppSettingsClickListener mAppSettingsClickListener;
-    private PackageManager mPm;
-
     private NotificationGuts mGutsContainer;
 
+    private OnClickListener mOnKeepShowing = v -> {
+        closeControls(v);
+    };
+
+    private OnClickListener mOnStopNotifications = v -> {
+        swapContent(false);
+    };
+
+    private OnClickListener mOnUndo = v -> {
+        swapContent(true);
+    };
+
     public NotificationInfo(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -98,141 +114,93 @@
     public void bindNotification(final PackageManager pm,
             final INotificationManager iNotificationManager,
             final String pkg,
-            final List<NotificationChannel> notificationChannels,
-            int startingUserImportance,
+            final NotificationChannel notificationChannel,
+            final int numChannels,
             final StatusBarNotification sbn,
-            OnSettingsClickListener onSettingsClick,
-            OnAppSettingsClickListener onAppSettingsClick,
-            OnClickListener onDoneClick,
-            CheckSaveListener checkSaveListener,
+            final CheckSaveListener checkSaveListener,
+            final OnSettingsClickListener onSettingsClick,
+            final OnAppSettingsClickListener onAppSettingsClick,
             final Set<String> nonBlockablePkgs)
             throws RemoteException {
         mINotificationManager = iNotificationManager;
         mPkg = pkg;
-        mNotificationChannels = notificationChannels;
-        mCheckSaveListener = checkSaveListener;
+        mNumNotificationChannels = numChannels;
         mSbn = sbn;
         mPm = pm;
         mAppSettingsClickListener = onAppSettingsClick;
-        mStartingUserImportance = startingUserImportance;
         mAppName = mPkg;
-        Drawable pkgicon = null;
-        CharSequence channelNameText = "";
-        ApplicationInfo info = null;
-        try {
-            info = pm.getApplicationInfo(mPkg,
-                    PackageManager.MATCH_UNINSTALLED_PACKAGES
-                            | PackageManager.MATCH_DISABLED_COMPONENTS
-                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                            | PackageManager.MATCH_DIRECT_BOOT_AWARE);
-            if (info != null) {
-                mAppUid = sbn.getUid();
-                mAppName = String.valueOf(pm.getApplicationLabel(info));
-                pkgicon = pm.getApplicationIcon(info);
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            // app is gone, just show package name and generic icon
-            pkgicon = pm.getDefaultActivityIcon();
-        }
-        ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
+        mCheckSaveListener = checkSaveListener;
+        mOnSettingsClickListener = onSettingsClick;
+        mSingleNotificationChannel = notificationChannel;
+        mStartingUserImportance = mChosenImportance = mSingleNotificationChannel.getImportance();
 
-        int numTotalChannels = iNotificationManager.getNumNotificationChannelsForPackage(
+        int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
                 pkg, mAppUid, false /* includeDeleted */);
-        if (mNotificationChannels.isEmpty()) {
+        if (mNumNotificationChannels == 0) {
             throw new IllegalArgumentException("bindNotification requires at least one channel");
         } else  {
-            if (mNotificationChannels.size() == 1) {
-                mSingleNotificationChannel = mNotificationChannels.get(0);
-                // Special behavior for the Default channel if no other channels have been defined.
-                mIsSingleDefaultChannel =
-                        (mSingleNotificationChannel.getId()
-                                .equals(NotificationChannel.DEFAULT_CHANNEL_ID) &&
-                        numTotalChannels <= 1);
-            } else {
-                mSingleNotificationChannel = null;
-                mIsSingleDefaultChannel = false;
-            }
+            // Special behavior for the Default channel if no other channels have been defined.
+            mIsSingleDefaultChannel = mNumNotificationChannels == 1
+                    && mSingleNotificationChannel.getId()
+                    .equals(NotificationChannel.DEFAULT_CHANNEL_ID)
+                    && numTotalChannels <= 1;
         }
 
-        boolean nonBlockable = false;
         try {
             final PackageInfo pkgInfo = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
             if (Utils.isSystemPackage(getResources(), pm, pkgInfo)) {
-                final int numChannels = mNotificationChannels.size();
-                for (int i = 0; i < numChannels; i++) {
-                    final NotificationChannel notificationChannel = mNotificationChannels.get(i);
-                    // If any of the system channels is not blockable, the bundle is nonblockable
-                    if (!notificationChannel.isBlockableSystem()) {
-                        nonBlockable = true;
-                        break;
-                    }
+                if (mSingleNotificationChannel != null
+                        && !mSingleNotificationChannel.isBlockableSystem()) {
+                    mNonblockable = true;
                 }
             }
         } catch (PackageManager.NameNotFoundException e) {
             // unlikely.
         }
         if (nonBlockablePkgs != null) {
-            nonBlockable |= nonBlockablePkgs.contains(pkg);
+            mNonblockable |= nonBlockablePkgs.contains(pkg);
         }
+        mNonblockable |= (mNumNotificationChannels > 1);
 
-        String channelsDescText;
-        mNumChannelsView = findViewById(R.id.num_channels_desc);
-        if (nonBlockable) {
-            channelsDescText = mContext.getString(R.string.notification_unblockable_desc);
-        } else if (mIsSingleDefaultChannel) {
-            channelsDescText = mContext.getString(R.string.notification_default_channel_desc);
-        } else {
-            switch (mNotificationChannels.size()) {
-                case 1:
-                    channelsDescText = String.format(mContext.getResources().getQuantityString(
-                            R.plurals.notification_num_channels_desc, numTotalChannels),
-                            numTotalChannels);
-                    break;
-                case 2:
-                    channelsDescText = mContext.getString(
-                            R.string.notification_channels_list_desc_2,
-                            mNotificationChannels.get(0).getName(),
-                            mNotificationChannels.get(1).getName());
-                    break;
-                default:
-                    final int numOthers = mNotificationChannels.size() - 2;
-                    channelsDescText = String.format(
-                            mContext.getResources().getQuantityString(
-                                    R.plurals.notification_channels_list_desc_2_and_others,
-                                    numOthers),
-                            mNotificationChannels.get(0).getName(),
-                            mNotificationChannels.get(1).getName(),
-                            numOthers);
+        bindHeader();
+        bindPrompt();
+        bindButtons();
+    }
+
+    private void bindHeader() throws RemoteException {
+        // 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();
         }
-        mNumChannelsView.setText(channelsDescText);
-
-        if (mSingleNotificationChannel == null) {
-            // Multiple channels don't use a channel name for the title.
-            channelNameText = mContext.getString(R.string.notification_num_channels,
-                    mNotificationChannels.size());
-        } else if (mIsSingleDefaultChannel || nonBlockable) {
-            // If this is the default channel or the app is unblockable,
-            // don't use our channel-specific text.
-            channelNameText = mContext.getString(R.string.notification_header_default_channel);
-        } else {
-            channelNameText = mSingleNotificationChannel.getName();
-        }
+        ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
         ((TextView) findViewById(R.id.pkgname)).setText(mAppName);
-        ((TextView) findViewById(R.id.channel_name)).setText(channelNameText);
 
         // Set group information if this channel has an associated group.
         CharSequence groupName = null;
         if (mSingleNotificationChannel != null && mSingleNotificationChannel.getGroup() != null) {
             final NotificationChannelGroup notificationChannelGroup =
-                    iNotificationManager.getNotificationChannelGroupForPackage(
-                            mSingleNotificationChannel.getGroup(), pkg, mAppUid);
+                    mINotificationManager.getNotificationChannelGroupForPackage(
+                            mSingleNotificationChannel.getGroup(), mPkg, mAppUid);
             if (notificationChannelGroup != null) {
                 groupName = notificationChannelGroup.getName();
             }
         }
-        TextView groupNameView = ((TextView) findViewById(R.id.group_name));
-        TextView groupDividerView = ((TextView) findViewById(R.id.pkg_group_divider));
+        TextView groupNameView = findViewById(R.id.group_name);
+        TextView groupDividerView = findViewById(R.id.pkg_group_divider);
         if (groupName != null) {
             groupNameView.setText(groupName);
             groupNameView.setVisibility(View.VISIBLE);
@@ -242,53 +210,55 @@
             groupDividerView.setVisibility(View.GONE);
         }
 
-        bindButtons(nonBlockable);
-
-        // Top-level importance group
-        mChannelDisabledView = findViewById(R.id.channel_disabled);
-        updateSecondaryText();
-
         // Settings button.
-        final TextView settingsButton = (TextView) findViewById(R.id.more_settings);
-        if (mAppUid >= 0 && onSettingsClick != null) {
+        final View settingsButton = findViewById(R.id.info);
+        if (mAppUid >= 0 && mOnSettingsClickListener != null) {
             settingsButton.setVisibility(View.VISIBLE);
             final int appUidF = mAppUid;
             settingsButton.setOnClickListener(
                     (View view) -> {
-                        onSettingsClick.onClick(view, mSingleNotificationChannel, appUidF);
+                        mOnSettingsClickListener.onClick(view,
+                                mNumNotificationChannels > 1 ? null : mSingleNotificationChannel,
+                                appUidF);
                     });
-            if (numTotalChannels <= 1 || nonBlockable) {
-                settingsButton.setText(R.string.notification_more_settings);
-            } else {
-                settingsButton.setText(R.string.notification_all_categories);
-            }
         } else {
             settingsButton.setVisibility(View.GONE);
         }
+    }
 
-        // Done button.
-        final TextView doneButton = (TextView) findViewById(R.id.done);
-        doneButton.setText(R.string.notification_done);
-        doneButton.setOnClickListener(onDoneClick);
+    private void bindPrompt() {
+        final TextView channelName = findViewById(R.id.channel_name);
+        final TextView blockPrompt = findViewById(R.id.block_prompt);
+        if (mNonblockable) {
+            if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
+                channelName.setVisibility(View.GONE);
+            } else {
+                channelName.setText(mSingleNotificationChannel.getName());
+            }
 
-        // Optional settings link
-        updateAppSettingsLink();
+            blockPrompt.setText(R.string.notification_unblockable_desc);
+        } else {
+            if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
+                channelName.setVisibility(View.GONE);
+                blockPrompt.setText(R.string.inline_keep_showing_app);
+            } else {
+                channelName.setText(mSingleNotificationChannel.getName());
+                blockPrompt.setText(R.string.inline_keep_showing);
+            }
+        }
     }
 
     private boolean hasImportanceChanged() {
-        return mSingleNotificationChannel != null &&
-                mChannelEnabledSwitch != null &&
-                mStartingUserImportance != getSelectedImportance();
+        return mSingleNotificationChannel != null && mStartingUserImportance != mChosenImportance;
     }
 
     private void saveImportance() {
-        if (!hasImportanceChanged()) {
+        if (mNonblockable || !hasImportanceChanged()) {
             return;
         }
-        final int selectedImportance = getSelectedImportance();
         MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
-                selectedImportance - mStartingUserImportance);
-        mSingleNotificationChannel.setImportance(selectedImportance);
+                mChosenImportance - mStartingUserImportance);
+        mSingleNotificationChannel.setImportance(mChosenImportance);
         mSingleNotificationChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
         try {
             mINotificationManager.updateNotificationChannelForPackage(
@@ -298,30 +268,78 @@
         }
     }
 
-    private int getSelectedImportance() {
-        if (!mChannelEnabledSwitch.isChecked()) {
-            return IMPORTANCE_NONE;
+    private void bindButtons() {
+        View block =  findViewById(R.id.block);
+        block.setOnClickListener(mOnStopNotifications);
+        TextView keep = findViewById(R.id.keep);
+        keep.setOnClickListener(mOnKeepShowing);
+        findViewById(R.id.undo).setOnClickListener(mOnUndo);
+
+        if (mNonblockable) {
+            keep.setText(R.string.notification_done);
+            block.setVisibility(GONE);
+        }
+
+        // app settings link
+        TextView settingsLinkView = findViewById(R.id.app_settings);
+        Intent settingsIntent = getAppSettingsIntent(mPm, mPkg, mSingleNotificationChannel,
+                mSbn.getId(), mSbn.getTag());
+        if (settingsIntent != null
+                && !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
+            settingsLinkView.setVisibility(View.VISIBLE);
+            settingsLinkView.setText(mContext.getString(R.string.notification_app_settings,
+                    mSbn.getNotification().getSettingsText()));
+            settingsLinkView.setOnClickListener((View view) -> {
+                mAppSettingsClickListener.onClick(view, settingsIntent);
+            });
         } else {
-            return mStartingUserImportance;
+            settingsLinkView.setVisibility(View.GONE);
         }
     }
 
-    private void bindButtons(final boolean nonBlockable) {
-        // Enabled Switch
-        mChannelEnabledSwitch = (Switch) findViewById(R.id.channel_enabled_switch);
-        mChannelEnabledSwitch.setChecked(
-                mStartingUserImportance != IMPORTANCE_NONE);
-        final boolean visible = !nonBlockable && mSingleNotificationChannel != null;
-        mChannelEnabledSwitch.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+    private void swapContent(boolean showPrompt) {
+        if (mExpandAnimation != null) {
+            mExpandAnimation.cancel();
+        }
 
-        // Callback when checked.
-        mChannelEnabledSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
-            if (mGutsContainer != null) {
-                mGutsContainer.resetFalsingCheck();
+        if (showPrompt) {
+            mChosenImportance = mStartingUserImportance;
+        } else {
+            mChosenImportance = IMPORTANCE_NONE;
+        }
+
+        View prompt = findViewById(R.id.prompt);
+        View confirmation = findViewById(R.id.confirmation);
+        ObjectAnimator promptAnim = ObjectAnimator.ofFloat(prompt, View.ALPHA,
+                prompt.getAlpha(), showPrompt ? 1f : 0f);
+        promptAnim.setInterpolator(showPrompt ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
+        ObjectAnimator confirmAnim = ObjectAnimator.ofFloat(confirmation, View.ALPHA,
+                confirmation.getAlpha(), showPrompt ? 0f : 1f);
+        confirmAnim.setInterpolator(showPrompt ? Interpolators.ALPHA_OUT : Interpolators.ALPHA_IN);
+
+        prompt.setVisibility(showPrompt ? VISIBLE : GONE);
+        confirmation.setVisibility(showPrompt ? GONE : VISIBLE);
+
+        mExpandAnimation = new AnimatorSet();
+        mExpandAnimation.playTogether(promptAnim, confirmAnim);
+        mExpandAnimation.setDuration(150);
+        mExpandAnimation.addListener(new AnimatorListenerAdapter() {
+            boolean cancelled = false;
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                cancelled = true;
             }
-            updateSecondaryText();
-            updateAppSettingsLink();
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!cancelled) {
+                    prompt.setVisibility(showPrompt ? VISIBLE : GONE);
+                    confirmation.setVisibility(showPrompt ? GONE : VISIBLE);
+                }
+            }
         });
+        mExpandAnimation.start();
     }
 
     @Override
@@ -339,35 +357,6 @@
         }
     }
 
-    private void updateSecondaryText() {
-        final boolean disabled = mSingleNotificationChannel != null &&
-                getSelectedImportance() == IMPORTANCE_NONE;
-        if (disabled) {
-            mChannelDisabledView.setVisibility(View.VISIBLE);
-            mNumChannelsView.setVisibility(View.GONE);
-        } else {
-            mChannelDisabledView.setVisibility(View.GONE);
-            mNumChannelsView.setVisibility(mIsSingleDefaultChannel ? View.INVISIBLE : View.VISIBLE);
-        }
-    }
-
-    private void updateAppSettingsLink() {
-        mSettingsLinkView = findViewById(R.id.app_settings);
-        Intent settingsIntent = getAppSettingsIntent(mPm, mPkg, mSingleNotificationChannel,
-                mSbn.getId(), mSbn.getTag());
-        if (settingsIntent != null && getSelectedImportance() != IMPORTANCE_NONE
-                && !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
-            mSettingsLinkView.setVisibility(View.VISIBLE);
-            mSettingsLinkView.setText(mContext.getString(R.string.notification_app_settings,
-                    mSbn.getNotification().getSettingsText()));
-            mSettingsLinkView.setOnClickListener((View view) -> {
-                mAppSettingsClickListener.onClick(view, settingsIntent);
-            });
-        } else {
-            mSettingsLinkView.setVisibility(View.GONE);
-        }
-    }
-
     private Intent getAppSettingsIntent(PackageManager pm, String packageName,
             NotificationChannel channel, int id, String tag) {
         Intent intent = new Intent(Intent.ACTION_MAIN)
@@ -390,6 +379,18 @@
         return intent;
     }
 
+    private void closeControls(View v) {
+        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 /* save */, false /* force */);
+    }
+
     @Override
     public void setGutsParent(NotificationGuts guts) {
         mGutsContainer = guts;
@@ -397,7 +398,7 @@
 
     @Override
     public boolean willBeRemoved() {
-        return mChannelEnabledSwitch != null && !mChannelEnabledSwitch.isChecked();
+        return hasImportanceChanged();
     }
 
     @Override