From 25593cc9b8e0fe13da8bf7bbf5683cc5f09c2a79 Mon Sep 17 00:00:00 2001 From: Matthew Ng Date: Wed, 12 Sep 2018 16:05:41 -0700 Subject: [PATCH] Refactored the contextual group of buttons that appear on the nav bar Refactored NavigationBarView's contextual buttons to keep track of just one button's visiblity with its container group. The visiblity is determined by the priority of the buttons. For example, accessibility has the highest priority, if that is visible, no other buttons can take its place, however if menu button is visible, then rotation can appear instead. Bug: 116041410 Test: atest NavigationBarContextTest Change-Id: Ic0762c7b7121a313b7c08989f9ab761426372c5c --- .../statusbar/phone/ContextualButton.java | 76 +++++++ .../phone/ContextualButtonGroup.java | 155 ++++++++++++++ .../phone/NavigationBarFragment.java | 2 +- .../statusbar/phone/NavigationBarView.java | 183 ++++------------ .../phone/RotationContextButton.java | 61 ++++++ .../statusbar/policy/KeyButtonDrawable.java | 19 ++ .../phone/NavigationBarContextTest.java | 199 ++++++++++++++++++ 7 files changed, 555 insertions(+), 140 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java new file mode 100644 index 0000000000000..4f957bfcbbccd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java @@ -0,0 +1,76 @@ +/* + * 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.phone; + +import android.annotation.DrawableRes; +import android.annotation.IdRes; +import android.content.Context; +import android.view.View; +import com.android.systemui.statusbar.policy.KeyButtonDrawable; +import com.android.systemui.statusbar.policy.KeyButtonView; + +/** + * Simple contextual button that is added to the {@link ContextualButtonGroup}. Extend if need extra + * functionality. + */ +public class ContextualButton extends ButtonDispatcher { + + protected final @DrawableRes int mIconResId; + + /** + * Create a contextual button that will use a {@link KeyButtonView} and + * {@link KeyButtonDrawable} get and show the button from xml to its icon drawable. + * @param buttonResId the button view from xml layout + * @param iconResId icon resource to be used + */ + public ContextualButton(@IdRes int buttonResId, @DrawableRes int iconResId) { + super(buttonResId); + mIconResId = iconResId; + } + + /** + * Reload the drawable from resource id, should reapply the previous dark intensity. + */ + public void updateIcon() { + final KeyButtonDrawable currentDrawable = getImageDrawable(); + KeyButtonDrawable drawable = getNewDrawable(); + if (currentDrawable != null) { + drawable.setDarkIntensity(currentDrawable.getDarkIntensity()); + } + setImageDrawable(drawable); + } + + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + + // Stop any active animations if hidden + final KeyButtonDrawable currentDrawable = getImageDrawable(); + if (visibility != View.VISIBLE && currentDrawable != null && currentDrawable.canAnimate()) { + currentDrawable.clearAnimationCallbacks(); + currentDrawable.resetAnimation(); + } + } + + protected KeyButtonDrawable getNewDrawable() { + return KeyButtonDrawable.create(getContext(), mIconResId, false /* shadow */); + } + + protected Context getContext() { + return getCurrentView().getContext(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java new file mode 100644 index 0000000000000..1b039663ab735 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java @@ -0,0 +1,155 @@ +/* + * 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.phone; + +import android.annotation.IdRes; +import android.annotation.NonNull; +import android.view.View; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +public class ContextualButtonGroup extends ButtonDispatcher { + private static final int INVALID_INDEX = -1; + + // List of pairs that contains the button and if the button was visible within this group + private final List mButtonData = new ArrayList<>(); + + public ContextualButtonGroup(@IdRes int containerId) { + super(containerId); + } + + /** + * Add a contextual button to the group. The order of adding increases in its priority. The + * priority is used to determine which button should be visible when setting multiple button's + * visibility {@see setButtonVisiblity}. + * @param button the button added to the group + */ + public void addButton(@NonNull ContextualButton button) { + mButtonData.add(new ButtonData(button)); + } + + public ContextualButton getContextButton(@IdRes int buttonResId) { + int index = getContextButtonIndex(buttonResId); + if (index != INVALID_INDEX) { + return mButtonData.get(index).button; + } + return null; + } + + public ContextualButton getVisibleContextButton() { + for (int i = mButtonData.size() - 1; i >= 0; --i) { + if (mButtonData.get(i).markedVisible) { + return mButtonData.get(i).button; + } + } + return null; + } + + /** + * Set the visibility of the button by {@param buttonResId} with {@param visible}. Only one + * button is shown at a time. The input button will only show up if it has higher priority than + * a previous button, otherwise it will be marked as visible and shown later if all higher + * priority buttons are invisible. Therefore hiding a button will show the next marked visible + * button. This group's view will be visible if at least one button is visible. + * @return if the button is visible after operation + * @throws RuntimeException if the input id does not match any of the ids in the group + */ + public int setButtonVisiblity(@IdRes int buttonResId, boolean visible) { + final int index = getContextButtonIndex(buttonResId); + if (index == INVALID_INDEX) { + throw new RuntimeException("Cannot find the button id of " + buttonResId + + " in context group"); + } + setVisibility(View.INVISIBLE); + mButtonData.get(index).markedVisible = visible; + + // Make all buttons invisible except the first markedVisible button + boolean alreadyFoundVisibleButton = false; + int i = mButtonData.size() - 1; + for (; i >= 0; --i) { + final ButtonData buttonData = mButtonData.get(i); + if (!alreadyFoundVisibleButton && buttonData.markedVisible) { + buttonData.setVisibility(View.VISIBLE); + setVisibility(View.VISIBLE); + alreadyFoundVisibleButton = true; + } else { + buttonData.setVisibility(View.INVISIBLE); + } + } + return mButtonData.get(index).button.getVisibility(); + } + + /** + * See if button is group visible. Group visible determines if a button can be visible when + * higher priority buttons go invisible. + * @param buttonResId the button to see if it is group visible + * @return true if button is group visible + */ + public boolean isButtonVisibleWithinGroup(@IdRes int buttonResId) { + final int index = getContextButtonIndex(buttonResId); + return index != INVALID_INDEX && mButtonData.get(index).markedVisible; + } + + /** + * Update all the icons that are attached to this group. This will get all the buttons to update + * their icons for their buttons. + */ + public void updateIcons() { + for (ButtonData data : mButtonData) { + data.button.updateIcon(); + } + } + + public void dump(PrintWriter pw) { + pw.println("ContextualButtonGroup {"); + pw.println(" getVisibleContextButton(): " + getVisibleContextButton()); + pw.println(" isVisible(): " + isVisible()); + pw.println(" mButtonData [ "); + for (int i = mButtonData.size() - 1; i >= 0; --i) { + final ButtonData data = mButtonData.get(i); + pw.println(" " + i + ": markedVisible=" + data.markedVisible + + " visible=" + data.button.getVisibility() + + " alpha=" + data.button.getAlpha()); + } + pw.println(" ]"); + pw.println(" }"); + } + + private int getContextButtonIndex(@IdRes int buttonResId) { + for (int i = 0; i < mButtonData.size(); ++i) { + if (mButtonData.get(i).button.getId() == buttonResId) { + return i; + } + } + return INVALID_INDEX; + } + + private final static class ButtonData { + ContextualButton button; + boolean markedVisible; + + ButtonData(ContextualButton button) { + this.button = button; + this.markedVisible = false; + } + + void setVisibility(int visiblity) { + button.setVisibility(visiblity); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 66486cedcfb59..cbbb0e3dea969 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -463,7 +463,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { style = rotationCCW ? R.style.RotateButtonCCWStart0 : R.style.RotateButtonCWStart0; } - mNavigationBarView.updateRotateSuggestionButtonStyle(style, true); + mNavigationBarView.updateRotateSuggestionButtonStyle(style); } if (mNavigationBarWindowState != WINDOW_STATE_SHOWING) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 9d13ea22b281a..aebcb9f27e24d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -36,8 +36,6 @@ import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Point; import android.graphics.Rect; -import android.graphics.drawable.AnimatedVectorDrawable; -import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -46,7 +44,6 @@ import androidx.annotation.ColorInt; import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; -import android.view.ContextThemeWrapper; import android.view.Display; import android.view.MotionEvent; import android.view.Surface; @@ -59,7 +56,6 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.view.inputmethod.InputMethodManager; import android.widget.FrameLayout; -import com.android.settingslib.Utils; import com.android.systemui.Dependency; import com.android.systemui.DockedStackExistsListener; import com.android.systemui.Interpolators; @@ -106,10 +102,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener