Loading packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml +80 −74 Original line number Diff line number Diff line Loading @@ -14,104 +14,110 @@ See the License for the specific language governing permissions and limitations under the License. --> <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"> <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"> <aapt:attr name="android:drawable"> <vector android:height="24dp" <vector android:name="root" android:width="24dp" android:viewportHeight="102" android:viewportWidth="102" android:tint="?attr/singleToneColor"> <group android:name="_R_G"> <group android:name="_R_G_L_0_G" android:translateX="53.086" android:translateY="48.907000000000004" android:pivotX="-2.083" android:pivotY="2.083" android:rotation="90"> <group android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0" android:rotation="100.1" android:scaleX="0.7979999999999999" android:scaleY="0.7979999999999999"> <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M17.15 -37.84 C30.19,-31.91 39.52,-19.62 41.9,-4.86 C42.15,-3.39 43.45,-2.31 44.95,-2.31 C46.88,-2.31 48.34,-4.06 48.05,-5.94 C44.37,-27.64 27.64,-45.91 0.84,-48.09 C-1.08,-48.25 -2.17,-45.91 -0.83,-44.53 C-0.83,-44.53 9.87,-33.83 9.87,-33.83 C10.67,-33.04 11.92,-33.04 12.76,-33.79 C12.76,-33.79 17.15,-37.84 17.15,-37.84c "/> android:height="24dp" android:viewportWidth="24.0" android:viewportHeight="24.0"> <group android:name="icon" android:pivotX="12" android:pivotY="12"> <!-- Tint color to be set directly --> <path android:fillColor="#FFFFFFFF" android:pathData="M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19H7V5h10v14z"/> </group> <group android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0" android:rotation="87.2" android:scaleX="0.77" android:scaleY="0.77"> <path android:name="_R_G_L_0_G_D_1_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-21.32 42.01 C-34.36,36.07 -43.68,23.78 -46.07,9.02 C-46.33,7.55 -47.62,6.47 -49.12,6.47 C-51.04,6.47 -52.51,8.23 -52.21,10.11 C-48.53,31.81 -31.81,50.08 -5.01,52.25 C-3.09,52.42 -2,50.08 -3.34,48.7 C-3.34,48.7 -14.04,38 -14.04,38 C-14.84,37.21 -16.11,37.19 -16.93,37.96 C-16.93,37.96 -21.32,42.01 -21.32,42.01c "/> </group> <path android:name="_R_G_L_0_G_D_2_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M40.77 9.4 C40.77,9.4 -9.4,-40.77 -9.4,-40.77 C-11.91,-43.28 -15.67,-43.28 -18.18,-40.77 C-18.18,-40.77 -44.94,-14.01 -44.94,-14.01 C-47.45,-11.5 -47.45,-7.74 -44.94,-5.23 C-44.94,-5.23 5.23,44.94 5.23,44.94 C7.74,47.45 11.51,47.45 14.01,44.94 C14.01,44.94 40.77,18.18 40.77,18.18 C43.28,15.67 43.28,11.91 40.77,9.4c M3.85 34.82 C3.85,34.82 -34.4,-3.44 -34.4,-3.44 C-34.4,-3.44 -7.64,-30.19 -7.64,-30.19 C-7.64,-30.19 30.61,8.06 30.61,8.06 C30.61,8.06 3.85,34.82 3.85,34.82c "/> </group> </group> <group android:name="time_group"/> </vector> </aapt:attr> <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"> <!-- Repeat all animations 3 times but don't fade out at the end --> <target android:name="root"> <aapt:attr name="android:animation"> <set android:ordering="together"> <objectAnimator android:propertyName="rotation" android:duration="333" android:startOffset="0" android:valueFrom="100.1" android:valueTo="0" android:valueType="floatType"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/> </aapt:attr> </objectAnimator> <set android:ordering="sequentially"> <!-- Linear fade in--> <objectAnimator android:propertyName="alpha" android:duration="100" android:valueFrom="0" android:valueTo="1" android:interpolator="@android:anim/linear_interpolator" /> <!-- Linear fade out --> <objectAnimator android:propertyName="alpha" android:duration="100" android:startOffset="1700" android:valueFrom="1" android:valueTo="0" android:interpolator="@android:anim/linear_interpolator"/> <!-- Linear fade in--> <objectAnimator android:propertyName="alpha" android:duration="100" android:startOffset="100" android:valueFrom="0" android:valueTo="1" android:interpolator="@android:anim/linear_interpolator" /> <!-- Linear fade out --> <objectAnimator android:propertyName="alpha" android:duration="100" android:startOffset="1700" android:valueFrom="1" android:valueTo="0" android:interpolator="@android:anim/linear_interpolator"/> <!-- Linear fade in--> <objectAnimator android:propertyName="alpha" android:duration="100" android:startOffset="100" android:valueFrom="0" android:valueTo="1" android:interpolator="@android:anim/linear_interpolator" /> </set> </aapt:attr> </target> <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"> <target android:name="icon"> <aapt:attr name="android:animation"> <set android:ordering="together"> <objectAnimator android:propertyName="scaleX" android:duration="333" android:startOffset="0" android:valueFrom="0.798" android:valueTo="1" android:valueType="floatType"> <set android:ordering="sequentially"> <!-- Icon rotation with start timing offset after fade in --> <objectAnimator android:propertyName="rotation" android:startOffset="100" android:duration="600" android:valueFrom="?attr/rotateButtonStartAngle" android:valueTo="?attr/rotateButtonEndAngle"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/> <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> </aapt:attr> </objectAnimator> <objectAnimator android:propertyName="scaleY" android:duration="333" android:startOffset="0" android:valueFrom="0.798" android:valueTo="1" android:valueType="floatType"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/> </aapt:attr> </objectAnimator> </set> </aapt:attr> </target> <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"> <aapt:attr name="android:animation"> <set android:ordering="together"> <objectAnimator android:propertyName="rotation" android:duration="333" android:startOffset="0" android:valueFrom="87.2" android:valueTo="0" android:valueType="floatType"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/> </aapt:attr> </objectAnimator> </set> </aapt:attr> </target> <!-- Reset rotation position for fade in --> <objectAnimator android:propertyName="rotation" android:startOffset="1300" android:duration="100" android:valueFrom="?attr/rotateButtonStartAngle" android:valueTo="?attr/rotateButtonStartAngle"/> <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"> <aapt:attr name="android:animation"> <set android:ordering="together"> <objectAnimator android:propertyName="scaleX" android:duration="333" android:startOffset="0" android:valueFrom="0.77" android:valueTo="1" android:valueType="floatType"> <!-- Icon rotation with start timing offset after fade in --> <objectAnimator android:propertyName="rotation" android:duration="600" android:valueFrom="?attr/rotateButtonStartAngle" android:valueTo="?attr/rotateButtonEndAngle"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/> <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> </aapt:attr> </objectAnimator> <objectAnimator android:propertyName="scaleY" android:duration="333" android:startOffset="0" android:valueFrom="0.77" android:valueTo="1" android:valueType="floatType"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/> </aapt:attr> </objectAnimator> </set> </aapt:attr> </target> <target android:name="_R_G_L_0_G"> <aapt:attr name="android:animation"> <set android:ordering="together"> <objectAnimator android:propertyName="rotation" android:duration="333" android:startOffset="0" android:valueFrom="90" android:valueTo="0" android:valueType="floatType"> <!-- Reset rotation position for fade in --> <objectAnimator android:propertyName="rotation" android:startOffset="1300" android:duration="100" android:valueFrom="?attr/rotateButtonStartAngle" android:valueTo="?attr/rotateButtonStartAngle"/> <!-- Icon rotation with start timing offset after fade in --> <objectAnimator android:propertyName="rotation" android:duration="600" android:valueFrom="?attr/rotateButtonStartAngle" android:valueTo="?attr/rotateButtonEndAngle"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/> <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> </aapt:attr> </objectAnimator> </set> </aapt:attr> </target> <target android:name="time_group"> <aapt:attr name="android:animation"> <set android:ordering="together"> <objectAnimator android:propertyName="translateX" android:duration="517" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/> </set> </aapt:attr> </target> </animated-vector> No newline at end of file packages/SystemUI/res/layout/rotate_suggestion.xmldeleted 100644 → 0 +0 −26 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2017 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. --> <com.android.systemui.statusbar.policy.KeyButtonView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rotate_suggestion" android:layout_width="@dimen/navigation_extra_key_width" android:layout_height="match_parent" android:layout_marginEnd="2dp" android:visibility="invisible" android:scaleType="centerInside" android:contentDescription="@string/accessibility_rotate_button" /> packages/SystemUI/res/values/attrs.xml +4 −0 Original line number Diff line number Diff line Loading @@ -136,5 +136,9 @@ <attr name="singleLineButtonPaddingHorizontal" format="dimension" /> <attr name="doubleLineButtonPaddingHorizontal" format="dimension" /> </declare-styleable> <!-- Used to style rotate suggestion button AVD animations --> <attr name="rotateButtonStartAngle" format="float" /> <attr name="rotateButtonEndAngle" format="float" /> </resources> packages/SystemUI/res/values/styles.xml +21 −0 Original line number Diff line number Diff line Loading @@ -485,4 +485,25 @@ <item name="android:colorBackground">?android:attr/colorSecondary</item> </style> <!-- Used to style rotate suggestion button AVD animations --> <style name="RotateButtonCCWStart0"> <item name="rotateButtonStartAngle">0</item> <item name="rotateButtonEndAngle">-90</item> </style> <style name="RotateButtonCCWStart90"> <item name="rotateButtonStartAngle">90</item> <item name="rotateButtonEndAngle">0</item> </style> <style name="RotateButtonCWStart0"> <item name="rotateButtonStartAngle">0</item> <item name="rotateButtonEndAngle">90</item> </style> <style name="RotateButtonCWStart90"> <item name="rotateButtonStartAngle">90</item> <item name="rotateButtonEndAngle">180</item> </style> </resources> packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +123 −23 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.database.ContentObserver; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; import android.inputmethodservice.InputMethodService; import android.os.Binder; import android.os.Bundle; Loading Loading @@ -77,8 +78,8 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.LatencyTracker; import com.android.systemui.Dependency; import com.android.systemui.OverviewProxyService; import com.android.systemui.Interpolators; import com.android.systemui.OverviewProxyService; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.assist.AssistManager; Loading Loading @@ -111,6 +112,9 @@ public class NavigationBarFragment extends Fragment implements Callbacks { private static final boolean DEBUG = false; private static final String EXTRA_DISABLE_STATE = "disabled_state"; private final static int BUTTON_FADE_IN_OUT_DURATION_MS = 100; private final static int ROTATE_BUTTON_LOOP_DURATION_MS = 2000; /** Allow some time inbetween the long press for back and recents. */ private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200; Loading Loading @@ -150,8 +154,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { private RotationLockController mRotationLockController; private TaskStackListenerImpl mTaskStackListener; private final Runnable mRemoveRotationProposal = () -> safeSetRotationButtonState(false); private Animator mRotateShowAnimator; private final Runnable mRemoveRotationProposal = () -> setRotateSuggestionButtonState(false); private Animator mRotateHideAnimator; private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() { Loading Loading @@ -364,29 +367,130 @@ public class NavigationBarFragment extends Fragment implements Callbacks { // rotate button if shown. if (!isValid) { safeSetRotationButtonState(false); setRotateSuggestionButtonState(false); return; } if (rotation == mWindowManager.getDefaultDisplay().getRotation()) { final int winRotation = mWindowManager.getDefaultDisplay().getRotation(); if (rotation == winRotation) { // Use this as a signal to remove any current suggestions getView().getHandler().removeCallbacks(mRemoveRotationProposal); safeSetRotationButtonState(false); setRotateSuggestionButtonState(false); } else { mLastRotationSuggestion = rotation; // Remember rotation for click safeSetRotationButtonState(true); // Update the icon style to change animation parameters if (mNavigationBarView != null) { final boolean rotationCCW = isRotationAnimationCCW(winRotation, rotation); int style; if (winRotation == Surface.ROTATION_0 || winRotation == Surface.ROTATION_180) { style = rotationCCW ? R.style.RotateButtonCCWStart90 : R.style.RotateButtonCWStart90; } else { // 90 or 270 style = rotationCCW ? R.style.RotateButtonCCWStart0 : R.style.RotateButtonCWStart0; } mNavigationBarView.updateRotateSuggestionButtonStyle(style, true); } setRotateSuggestionButtonState(true); rescheduleRotationTimeout(false); mMetricsLogger.visible(MetricsEvent.ROTATION_SUGGESTION_SHOWN); } } private void safeSetRotationButtonState(boolean vis) { if (mNavigationBarView != null) mNavigationBarView.setRotateSuggestionButtonState(vis); private boolean isRotationAnimationCCW(int from, int to) { // All 180deg WM rotation animations are CCW, match that if (from == Surface.ROTATION_0 && to == Surface.ROTATION_90) return false; if (from == Surface.ROTATION_0 && to == Surface.ROTATION_180) return true; //180d so CCW if (from == Surface.ROTATION_0 && to == Surface.ROTATION_270) return true; if (from == Surface.ROTATION_90 && to == Surface.ROTATION_0) return true; if (from == Surface.ROTATION_90 && to == Surface.ROTATION_180) return false; if (from == Surface.ROTATION_90 && to == Surface.ROTATION_270) return true; //180d so CCW if (from == Surface.ROTATION_180 && to == Surface.ROTATION_0) return true; //180d so CCW if (from == Surface.ROTATION_180 && to == Surface.ROTATION_90) return true; if (from == Surface.ROTATION_180 && to == Surface.ROTATION_270) return false; if (from == Surface.ROTATION_270 && to == Surface.ROTATION_0) return false; if (from == Surface.ROTATION_270 && to == Surface.ROTATION_90) return true; //180d so CCW if (from == Surface.ROTATION_270 && to == Surface.ROTATION_180) return true; return false; // Default } private void safeSetRotationButtonState(boolean vis, boolean force) { if (mNavigationBarView != null) { mNavigationBarView.setRotateSuggestionButtonState(vis, force); public void setRotateSuggestionButtonState(final boolean visible) { setRotateSuggestionButtonState(visible, false); } public void setRotateSuggestionButtonState(final boolean visible, final boolean force) { if (mNavigationBarView == null) return; // At any point the the button can become invisible because an a11y service became active. // Similarly, a call to make the button visible may be rejected because an a11y service is // active. Must account for this. ButtonDispatcher rotBtn = mNavigationBarView.getRotateSuggestionButton(); final boolean currentlyVisible = mNavigationBarView.isRotateButtonVisible(); // Rerun a show animation to indicate change but don't rerun a hide animation if (!visible && !currentlyVisible) return; View view = rotBtn.getCurrentView(); if (view == null) return; KeyButtonDrawable kbd = rotBtn.getImageDrawable(); if (kbd == null) return; // The KBD and AVD is recreated every new valid suggestion because of style changes. AnimatedVectorDrawable animIcon = null; if (kbd.getDrawable(0) instanceof AnimatedVectorDrawable) { animIcon = (AnimatedVectorDrawable) kbd.getDrawable(0); } if (visible) { // Appear and change (cannot force) // Stop any currently running hide animations if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) { mRotateHideAnimator.pause(); } // Reset the alpha if any has changed due to hide animation view.setAlpha(1f); // Run the rotate icon's animation if it has one if (animIcon != null) { animIcon.reset(); animIcon.start(); } // Set visibility, may fail if a11y service is active. // If invisible, call will stop animation. mNavigationBarView.setRotateButtonVisibility(true); } else { // Hide if (force) { // If a hide animator is running stop it and make invisible if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) { mRotateHideAnimator.pause(); } mNavigationBarView.setRotateButtonVisibility(false); return; } // Don't start any new hide animations if one is running if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return; ObjectAnimator fadeOut = ObjectAnimator.ofFloat(view, "alpha", 0f); fadeOut.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS); fadeOut.setInterpolator(Interpolators.LINEAR); fadeOut.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mNavigationBarView.setRotateButtonVisibility(false); } }); mRotateHideAnimator = fadeOut; fadeOut.start(); } } Loading @@ -394,13 +498,9 @@ public class NavigationBarFragment extends Fragment implements Callbacks { // May be called due to a new rotation proposal or a change in hover state if (reasonHover) { // Don't reschedule if a hide animator is running if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) { return; } if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return; // Don't reschedule if not visible if (mNavigationBarView.getRotateSuggestionButton().getVisibility() != View.VISIBLE) { return; } if (!mNavigationBarView.isRotateButtonVisible()) return; } Handler h = getView().getHandler(); Loading Loading @@ -827,7 +927,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { if (shouldOverrideUserLockPrefs(rotation)) { mRotationLockController.setRotationLockedAtAngle(true, rotation); } safeSetRotationButtonState(false, true); setRotateSuggestionButtonState(false, true); } if (mNavigationBarView != null Loading Loading @@ -863,22 +963,22 @@ public class NavigationBarFragment extends Fragment implements Callbacks { @Override public void onTaskStackChanged() { safeSetRotationButtonState(false); setRotateSuggestionButtonState(false); } @Override public void onTaskRemoved(int taskId) { safeSetRotationButtonState(false); setRotateSuggestionButtonState(false); } @Override public void onTaskMovedToFront(int taskId) { safeSetRotationButtonState(false); setRotateSuggestionButtonState(false); } @Override public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { safeSetRotationButtonState(false); setRotateSuggestionButtonState(false); } } Loading Loading
packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml +80 −74 Original line number Diff line number Diff line Loading @@ -14,104 +14,110 @@ See the License for the specific language governing permissions and limitations under the License. --> <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"> <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"> <aapt:attr name="android:drawable"> <vector android:height="24dp" <vector android:name="root" android:width="24dp" android:viewportHeight="102" android:viewportWidth="102" android:tint="?attr/singleToneColor"> <group android:name="_R_G"> <group android:name="_R_G_L_0_G" android:translateX="53.086" android:translateY="48.907000000000004" android:pivotX="-2.083" android:pivotY="2.083" android:rotation="90"> <group android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0" android:rotation="100.1" android:scaleX="0.7979999999999999" android:scaleY="0.7979999999999999"> <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M17.15 -37.84 C30.19,-31.91 39.52,-19.62 41.9,-4.86 C42.15,-3.39 43.45,-2.31 44.95,-2.31 C46.88,-2.31 48.34,-4.06 48.05,-5.94 C44.37,-27.64 27.64,-45.91 0.84,-48.09 C-1.08,-48.25 -2.17,-45.91 -0.83,-44.53 C-0.83,-44.53 9.87,-33.83 9.87,-33.83 C10.67,-33.04 11.92,-33.04 12.76,-33.79 C12.76,-33.79 17.15,-37.84 17.15,-37.84c "/> android:height="24dp" android:viewportWidth="24.0" android:viewportHeight="24.0"> <group android:name="icon" android:pivotX="12" android:pivotY="12"> <!-- Tint color to be set directly --> <path android:fillColor="#FFFFFFFF" android:pathData="M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19H7V5h10v14z"/> </group> <group android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0" android:rotation="87.2" android:scaleX="0.77" android:scaleY="0.77"> <path android:name="_R_G_L_0_G_D_1_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-21.32 42.01 C-34.36,36.07 -43.68,23.78 -46.07,9.02 C-46.33,7.55 -47.62,6.47 -49.12,6.47 C-51.04,6.47 -52.51,8.23 -52.21,10.11 C-48.53,31.81 -31.81,50.08 -5.01,52.25 C-3.09,52.42 -2,50.08 -3.34,48.7 C-3.34,48.7 -14.04,38 -14.04,38 C-14.84,37.21 -16.11,37.19 -16.93,37.96 C-16.93,37.96 -21.32,42.01 -21.32,42.01c "/> </group> <path android:name="_R_G_L_0_G_D_2_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M40.77 9.4 C40.77,9.4 -9.4,-40.77 -9.4,-40.77 C-11.91,-43.28 -15.67,-43.28 -18.18,-40.77 C-18.18,-40.77 -44.94,-14.01 -44.94,-14.01 C-47.45,-11.5 -47.45,-7.74 -44.94,-5.23 C-44.94,-5.23 5.23,44.94 5.23,44.94 C7.74,47.45 11.51,47.45 14.01,44.94 C14.01,44.94 40.77,18.18 40.77,18.18 C43.28,15.67 43.28,11.91 40.77,9.4c M3.85 34.82 C3.85,34.82 -34.4,-3.44 -34.4,-3.44 C-34.4,-3.44 -7.64,-30.19 -7.64,-30.19 C-7.64,-30.19 30.61,8.06 30.61,8.06 C30.61,8.06 3.85,34.82 3.85,34.82c "/> </group> </group> <group android:name="time_group"/> </vector> </aapt:attr> <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"> <!-- Repeat all animations 3 times but don't fade out at the end --> <target android:name="root"> <aapt:attr name="android:animation"> <set android:ordering="together"> <objectAnimator android:propertyName="rotation" android:duration="333" android:startOffset="0" android:valueFrom="100.1" android:valueTo="0" android:valueType="floatType"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/> </aapt:attr> </objectAnimator> <set android:ordering="sequentially"> <!-- Linear fade in--> <objectAnimator android:propertyName="alpha" android:duration="100" android:valueFrom="0" android:valueTo="1" android:interpolator="@android:anim/linear_interpolator" /> <!-- Linear fade out --> <objectAnimator android:propertyName="alpha" android:duration="100" android:startOffset="1700" android:valueFrom="1" android:valueTo="0" android:interpolator="@android:anim/linear_interpolator"/> <!-- Linear fade in--> <objectAnimator android:propertyName="alpha" android:duration="100" android:startOffset="100" android:valueFrom="0" android:valueTo="1" android:interpolator="@android:anim/linear_interpolator" /> <!-- Linear fade out --> <objectAnimator android:propertyName="alpha" android:duration="100" android:startOffset="1700" android:valueFrom="1" android:valueTo="0" android:interpolator="@android:anim/linear_interpolator"/> <!-- Linear fade in--> <objectAnimator android:propertyName="alpha" android:duration="100" android:startOffset="100" android:valueFrom="0" android:valueTo="1" android:interpolator="@android:anim/linear_interpolator" /> </set> </aapt:attr> </target> <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"> <target android:name="icon"> <aapt:attr name="android:animation"> <set android:ordering="together"> <objectAnimator android:propertyName="scaleX" android:duration="333" android:startOffset="0" android:valueFrom="0.798" android:valueTo="1" android:valueType="floatType"> <set android:ordering="sequentially"> <!-- Icon rotation with start timing offset after fade in --> <objectAnimator android:propertyName="rotation" android:startOffset="100" android:duration="600" android:valueFrom="?attr/rotateButtonStartAngle" android:valueTo="?attr/rotateButtonEndAngle"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/> <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> </aapt:attr> </objectAnimator> <objectAnimator android:propertyName="scaleY" android:duration="333" android:startOffset="0" android:valueFrom="0.798" android:valueTo="1" android:valueType="floatType"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/> </aapt:attr> </objectAnimator> </set> </aapt:attr> </target> <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"> <aapt:attr name="android:animation"> <set android:ordering="together"> <objectAnimator android:propertyName="rotation" android:duration="333" android:startOffset="0" android:valueFrom="87.2" android:valueTo="0" android:valueType="floatType"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/> </aapt:attr> </objectAnimator> </set> </aapt:attr> </target> <!-- Reset rotation position for fade in --> <objectAnimator android:propertyName="rotation" android:startOffset="1300" android:duration="100" android:valueFrom="?attr/rotateButtonStartAngle" android:valueTo="?attr/rotateButtonStartAngle"/> <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"> <aapt:attr name="android:animation"> <set android:ordering="together"> <objectAnimator android:propertyName="scaleX" android:duration="333" android:startOffset="0" android:valueFrom="0.77" android:valueTo="1" android:valueType="floatType"> <!-- Icon rotation with start timing offset after fade in --> <objectAnimator android:propertyName="rotation" android:duration="600" android:valueFrom="?attr/rotateButtonStartAngle" android:valueTo="?attr/rotateButtonEndAngle"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/> <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> </aapt:attr> </objectAnimator> <objectAnimator android:propertyName="scaleY" android:duration="333" android:startOffset="0" android:valueFrom="0.77" android:valueTo="1" android:valueType="floatType"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/> </aapt:attr> </objectAnimator> </set> </aapt:attr> </target> <target android:name="_R_G_L_0_G"> <aapt:attr name="android:animation"> <set android:ordering="together"> <objectAnimator android:propertyName="rotation" android:duration="333" android:startOffset="0" android:valueFrom="90" android:valueTo="0" android:valueType="floatType"> <!-- Reset rotation position for fade in --> <objectAnimator android:propertyName="rotation" android:startOffset="1300" android:duration="100" android:valueFrom="?attr/rotateButtonStartAngle" android:valueTo="?attr/rotateButtonStartAngle"/> <!-- Icon rotation with start timing offset after fade in --> <objectAnimator android:propertyName="rotation" android:duration="600" android:valueFrom="?attr/rotateButtonStartAngle" android:valueTo="?attr/rotateButtonEndAngle"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/> <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> </aapt:attr> </objectAnimator> </set> </aapt:attr> </target> <target android:name="time_group"> <aapt:attr name="android:animation"> <set android:ordering="together"> <objectAnimator android:propertyName="translateX" android:duration="517" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/> </set> </aapt:attr> </target> </animated-vector> No newline at end of file
packages/SystemUI/res/layout/rotate_suggestion.xmldeleted 100644 → 0 +0 −26 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2017 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. --> <com.android.systemui.statusbar.policy.KeyButtonView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rotate_suggestion" android:layout_width="@dimen/navigation_extra_key_width" android:layout_height="match_parent" android:layout_marginEnd="2dp" android:visibility="invisible" android:scaleType="centerInside" android:contentDescription="@string/accessibility_rotate_button" />
packages/SystemUI/res/values/attrs.xml +4 −0 Original line number Diff line number Diff line Loading @@ -136,5 +136,9 @@ <attr name="singleLineButtonPaddingHorizontal" format="dimension" /> <attr name="doubleLineButtonPaddingHorizontal" format="dimension" /> </declare-styleable> <!-- Used to style rotate suggestion button AVD animations --> <attr name="rotateButtonStartAngle" format="float" /> <attr name="rotateButtonEndAngle" format="float" /> </resources>
packages/SystemUI/res/values/styles.xml +21 −0 Original line number Diff line number Diff line Loading @@ -485,4 +485,25 @@ <item name="android:colorBackground">?android:attr/colorSecondary</item> </style> <!-- Used to style rotate suggestion button AVD animations --> <style name="RotateButtonCCWStart0"> <item name="rotateButtonStartAngle">0</item> <item name="rotateButtonEndAngle">-90</item> </style> <style name="RotateButtonCCWStart90"> <item name="rotateButtonStartAngle">90</item> <item name="rotateButtonEndAngle">0</item> </style> <style name="RotateButtonCWStart0"> <item name="rotateButtonStartAngle">0</item> <item name="rotateButtonEndAngle">90</item> </style> <style name="RotateButtonCWStart90"> <item name="rotateButtonStartAngle">90</item> <item name="rotateButtonEndAngle">180</item> </style> </resources>
packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +123 −23 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.database.ContentObserver; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; import android.inputmethodservice.InputMethodService; import android.os.Binder; import android.os.Bundle; Loading Loading @@ -77,8 +78,8 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.LatencyTracker; import com.android.systemui.Dependency; import com.android.systemui.OverviewProxyService; import com.android.systemui.Interpolators; import com.android.systemui.OverviewProxyService; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.assist.AssistManager; Loading Loading @@ -111,6 +112,9 @@ public class NavigationBarFragment extends Fragment implements Callbacks { private static final boolean DEBUG = false; private static final String EXTRA_DISABLE_STATE = "disabled_state"; private final static int BUTTON_FADE_IN_OUT_DURATION_MS = 100; private final static int ROTATE_BUTTON_LOOP_DURATION_MS = 2000; /** Allow some time inbetween the long press for back and recents. */ private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200; Loading Loading @@ -150,8 +154,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { private RotationLockController mRotationLockController; private TaskStackListenerImpl mTaskStackListener; private final Runnable mRemoveRotationProposal = () -> safeSetRotationButtonState(false); private Animator mRotateShowAnimator; private final Runnable mRemoveRotationProposal = () -> setRotateSuggestionButtonState(false); private Animator mRotateHideAnimator; private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() { Loading Loading @@ -364,29 +367,130 @@ public class NavigationBarFragment extends Fragment implements Callbacks { // rotate button if shown. if (!isValid) { safeSetRotationButtonState(false); setRotateSuggestionButtonState(false); return; } if (rotation == mWindowManager.getDefaultDisplay().getRotation()) { final int winRotation = mWindowManager.getDefaultDisplay().getRotation(); if (rotation == winRotation) { // Use this as a signal to remove any current suggestions getView().getHandler().removeCallbacks(mRemoveRotationProposal); safeSetRotationButtonState(false); setRotateSuggestionButtonState(false); } else { mLastRotationSuggestion = rotation; // Remember rotation for click safeSetRotationButtonState(true); // Update the icon style to change animation parameters if (mNavigationBarView != null) { final boolean rotationCCW = isRotationAnimationCCW(winRotation, rotation); int style; if (winRotation == Surface.ROTATION_0 || winRotation == Surface.ROTATION_180) { style = rotationCCW ? R.style.RotateButtonCCWStart90 : R.style.RotateButtonCWStart90; } else { // 90 or 270 style = rotationCCW ? R.style.RotateButtonCCWStart0 : R.style.RotateButtonCWStart0; } mNavigationBarView.updateRotateSuggestionButtonStyle(style, true); } setRotateSuggestionButtonState(true); rescheduleRotationTimeout(false); mMetricsLogger.visible(MetricsEvent.ROTATION_SUGGESTION_SHOWN); } } private void safeSetRotationButtonState(boolean vis) { if (mNavigationBarView != null) mNavigationBarView.setRotateSuggestionButtonState(vis); private boolean isRotationAnimationCCW(int from, int to) { // All 180deg WM rotation animations are CCW, match that if (from == Surface.ROTATION_0 && to == Surface.ROTATION_90) return false; if (from == Surface.ROTATION_0 && to == Surface.ROTATION_180) return true; //180d so CCW if (from == Surface.ROTATION_0 && to == Surface.ROTATION_270) return true; if (from == Surface.ROTATION_90 && to == Surface.ROTATION_0) return true; if (from == Surface.ROTATION_90 && to == Surface.ROTATION_180) return false; if (from == Surface.ROTATION_90 && to == Surface.ROTATION_270) return true; //180d so CCW if (from == Surface.ROTATION_180 && to == Surface.ROTATION_0) return true; //180d so CCW if (from == Surface.ROTATION_180 && to == Surface.ROTATION_90) return true; if (from == Surface.ROTATION_180 && to == Surface.ROTATION_270) return false; if (from == Surface.ROTATION_270 && to == Surface.ROTATION_0) return false; if (from == Surface.ROTATION_270 && to == Surface.ROTATION_90) return true; //180d so CCW if (from == Surface.ROTATION_270 && to == Surface.ROTATION_180) return true; return false; // Default } private void safeSetRotationButtonState(boolean vis, boolean force) { if (mNavigationBarView != null) { mNavigationBarView.setRotateSuggestionButtonState(vis, force); public void setRotateSuggestionButtonState(final boolean visible) { setRotateSuggestionButtonState(visible, false); } public void setRotateSuggestionButtonState(final boolean visible, final boolean force) { if (mNavigationBarView == null) return; // At any point the the button can become invisible because an a11y service became active. // Similarly, a call to make the button visible may be rejected because an a11y service is // active. Must account for this. ButtonDispatcher rotBtn = mNavigationBarView.getRotateSuggestionButton(); final boolean currentlyVisible = mNavigationBarView.isRotateButtonVisible(); // Rerun a show animation to indicate change but don't rerun a hide animation if (!visible && !currentlyVisible) return; View view = rotBtn.getCurrentView(); if (view == null) return; KeyButtonDrawable kbd = rotBtn.getImageDrawable(); if (kbd == null) return; // The KBD and AVD is recreated every new valid suggestion because of style changes. AnimatedVectorDrawable animIcon = null; if (kbd.getDrawable(0) instanceof AnimatedVectorDrawable) { animIcon = (AnimatedVectorDrawable) kbd.getDrawable(0); } if (visible) { // Appear and change (cannot force) // Stop any currently running hide animations if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) { mRotateHideAnimator.pause(); } // Reset the alpha if any has changed due to hide animation view.setAlpha(1f); // Run the rotate icon's animation if it has one if (animIcon != null) { animIcon.reset(); animIcon.start(); } // Set visibility, may fail if a11y service is active. // If invisible, call will stop animation. mNavigationBarView.setRotateButtonVisibility(true); } else { // Hide if (force) { // If a hide animator is running stop it and make invisible if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) { mRotateHideAnimator.pause(); } mNavigationBarView.setRotateButtonVisibility(false); return; } // Don't start any new hide animations if one is running if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return; ObjectAnimator fadeOut = ObjectAnimator.ofFloat(view, "alpha", 0f); fadeOut.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS); fadeOut.setInterpolator(Interpolators.LINEAR); fadeOut.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mNavigationBarView.setRotateButtonVisibility(false); } }); mRotateHideAnimator = fadeOut; fadeOut.start(); } } Loading @@ -394,13 +498,9 @@ public class NavigationBarFragment extends Fragment implements Callbacks { // May be called due to a new rotation proposal or a change in hover state if (reasonHover) { // Don't reschedule if a hide animator is running if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) { return; } if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return; // Don't reschedule if not visible if (mNavigationBarView.getRotateSuggestionButton().getVisibility() != View.VISIBLE) { return; } if (!mNavigationBarView.isRotateButtonVisible()) return; } Handler h = getView().getHandler(); Loading Loading @@ -827,7 +927,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { if (shouldOverrideUserLockPrefs(rotation)) { mRotationLockController.setRotationLockedAtAngle(true, rotation); } safeSetRotationButtonState(false, true); setRotateSuggestionButtonState(false, true); } if (mNavigationBarView != null Loading Loading @@ -863,22 +963,22 @@ public class NavigationBarFragment extends Fragment implements Callbacks { @Override public void onTaskStackChanged() { safeSetRotationButtonState(false); setRotateSuggestionButtonState(false); } @Override public void onTaskRemoved(int taskId) { safeSetRotationButtonState(false); setRotateSuggestionButtonState(false); } @Override public void onTaskMovedToFront(int taskId) { safeSetRotationButtonState(false); setRotateSuggestionButtonState(false); } @Override public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { safeSetRotationButtonState(false); setRotateSuggestionButtonState(false); } } Loading