Interim quick settings update.

Make existing QS panel available via pulldown from header
(or keyguard status view on keyguard), update the affordances
as a hint.

Don't allow QS to scroll, cap to max rows.

Add scrim over panel to indicate that this is purely temporary.

Bug:14081801
Bug:14059974
Change-Id: I166033975cbc44b91f45ee70ea5c7540390670dd
This commit is contained in:
John Spurlock
2014-04-15 16:14:46 -04:00
parent 33ac0dfc9f
commit 73203ebf97
27 changed files with 467 additions and 172 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 623 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 893 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 940 B

After

Width:  |  Height:  |  Size: 537 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 939 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -14,18 +14,12 @@
limitations under the License.
-->
<com.android.systemui.statusbar.phone.QuickSettingsScrollView
<com.android.systemui.statusbar.phone.QuickSettingsContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/quick_settings_container"
android:padding="@dimen/notification_side_padding"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/close_handle_underlap"
android:overScrollMode="ifContentScrolls"
>
<com.android.systemui.statusbar.phone.QuickSettingsContainerView
android:id="@+id/quick_settings_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:columnCount="@integer/quick_settings_num_columns"
/>
</com.android.systemui.statusbar.phone.QuickSettingsScrollView>
android:background="#5f000000"
android:animateLayoutChanges="true"
android:columnCount="@integer/quick_settings_num_columns" />

View File

@@ -41,7 +41,7 @@
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="right|top"
android:layout_marginTop="@*android:dimen/status_bar_height"
android:layout_marginTop="@dimen/status_bar_height"
android:visibility="gone" />
<LinearLayout

View File

@@ -27,14 +27,14 @@
<include layout="@layout/status_bar"
android:layout_width="match_parent"
android:layout_height="@*android:dimen/status_bar_height" />
android:layout_height="@dimen/status_bar_height" />
<com.android.systemui.statusbar.phone.PanelHolder
android:id="@+id/panel_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/panel_holder_padding_top"
android:layout_marginBottom="@*android:dimen/navigation_bar_height">
android:layout_marginBottom="@dimen/navigation_bar_height">
<include layout="@layout/status_bar_expanded"
android:layout_width="@dimen/notification_panel_width"
android:layout_height="wrap_content"

View File

@@ -27,6 +27,9 @@
<!-- The number of columns in the QuickSettings -->
<integer name="quick_settings_num_columns">6</integer>
<!-- The maximum number of rows in the QuickSettings -->
<integer name="quick_settings_max_rows">2</integer>
<!-- The number of columns that the top level tiles span in the QuickSettings -->
<integer name="quick_settings_user_time_settings_tile_span">2</integer>
</resources>

View File

@@ -26,6 +26,9 @@
<!-- The number of columns in the QuickSettings -->
<integer name="quick_settings_num_columns">3</integer>
<!-- The maximum number of rows in the QuickSettings -->
<integer name="quick_settings_max_rows">4</integer>
<!-- The number of columns that the top level tiles span in the QuickSettings -->
<integer name="quick_settings_user_time_settings_tile_span">1</integer>

View File

@@ -81,6 +81,12 @@
<!-- The number of columns in the QuickSettings -->
<integer name="quick_settings_num_columns">3</integer>
<!-- The maximum number of rows in the QuickSettings -->
<integer name="quick_settings_max_rows">4</integer>
<!-- The maximum number of rows in the QuickSettings when on the keyguard -->
<integer name="quick_settings_max_rows_keyguard">3</integer>
<!-- The number of columns that the top level tiles span in the QuickSettings -->
<integer name="quick_settings_user_time_settings_tile_span">1</integer>

View File

@@ -269,4 +269,7 @@
<!-- Camera affordance drag distance -->
<dimen name="camera_drag_distance">100dp</dimen>
<dimen name="quick_settings_tmp_scrim_stroke_width">8dp</dimen>
<dimen name="quick_settings_tmp_scrim_text_size">30dp</dimen>
</resources>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<resources>
<dimen name="status_bar_height">@*android:dimen/status_bar_height</dimen>
<dimen name="navigation_bar_height">@*android:dimen/navigation_bar_height</dimen>
<drawable name="notification_quantum_bg">@*android:drawable/notification_quantum_bg</drawable>
</resources>

View File

@@ -30,11 +30,14 @@ public class NotificationPanelView extends PanelView {
public static final boolean DEBUG_GESTURES = true;
PhoneStatusBar mStatusBar;
private View mHeader;
private View mKeyguardStatusView;
private NotificationStackScrollLayout mNotificationStackScroller;
private int[] mTempLocation = new int[2];
private int[] mTempChildLocation = new int[2];
private View mNotificationParent;
private boolean mTrackingSettings;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -59,6 +62,8 @@ public class NotificationPanelView extends PanelView {
protected void onFinishInflate() {
super.onFinishInflate();
mHeader = findViewById(R.id.header);
mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
mNotificationStackScroller = (NotificationStackScrollLayout)
findViewById(R.id.notification_stack_scroller);
mNotificationParent = findViewById(R.id.notification_container_parent);
@@ -98,10 +103,39 @@ public class NotificationPanelView extends PanelView {
return mTempChildLocation[1] - mTempLocation[1];
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// intercept for quick settings
if (event.getAction() == MotionEvent.ACTION_DOWN) {
final View target = mStatusBar.isOnKeyguard() ? mKeyguardStatusView : mHeader;
final boolean inTarget = PhoneStatusBar.inBounds(target, event, true);
if (inTarget && !isInSettings()) {
mTrackingSettings = true;
return true;
}
if (!inTarget && isInSettings()) {
mTrackingSettings = true;
return true;
}
}
return super.onInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO: Handle doublefinger swipe to notifications again. Look at history for a reference
// implementation.
if (mTrackingSettings) {
mStatusBar.onSettingsEvent(event);
if (event.getAction() == MotionEvent.ACTION_UP
|| event.getAction() == MotionEvent.ACTION_CANCEL) {
mTrackingSettings = false;
}
return true;
}
if (isInSettings()) {
return true;
}
return super.onTouchEvent(event);
}

View File

@@ -73,6 +73,7 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewPropertyAnimator;
@@ -97,11 +98,9 @@ import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.InterceptedNotifications;
import com.android.systemui.statusbar.LatestItemView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.NotificationOverflowContainer;
import com.android.systemui.statusbar.NotificationOverflowIconsView;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -233,8 +232,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
int mKeyguardMaxNotificationCount;
View mDateTimeView;
View mClearButton;
ImageView mSettingsButton, mNotificationButton;
View mKeyguardSettingsFlipButton;
FlipperButton mHeaderFlipper, mKeyguardFlipper;
// carrier/wifi label
private TextView mCarrierLabel;
@@ -314,9 +312,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " +
"selfChange=%s userSetup=%s mUserSetup=%s",
selfChange, userSetup, mUserSetup));
if (mSettingsButton != null && mHasFlipSettings) {
mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE);
}
mHeaderFlipper.userSetup(userSetup);
mKeyguardFlipper.userSetup(userSetup);
if (mSettingsPanel != null) {
mSettingsPanel.setEnabled(userSetup);
}
@@ -371,6 +369,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
private Runnable mOnFlipRunnable;
private InterceptedNotifications mIntercepted;
private VelocityTracker mSettingsTracker;
private float mSettingsDownY;
private boolean mSettingsCancelled;
private boolean mSettingsClosing;
private int mNotificationPadding;
private final OnChildLocationsChangedListener mOnChildLocationsChangedListener =
new OnChildLocationsChangedListener() {
@@ -631,35 +634,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
mDateTimeView.setEnabled(true);
}
mSettingsButton = (ImageView) mStatusBarWindow.findViewById(R.id.settings_button);
if (mSettingsButton != null) {
mSettingsButton.setOnClickListener(mSettingsButtonListener);
if (mHasSettingsPanel) {
if (mStatusBarView.hasFullWidthNotifications()) {
// the settings panel is hiding behind this button
mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
mSettingsButton.setVisibility(View.VISIBLE);
} else {
// there is a settings panel, but it's on the other side of the (large) screen
final View buttonHolder = mStatusBarWindow.findViewById(
R.id.settings_button_holder);
if (buttonHolder != null) {
buttonHolder.setVisibility(View.GONE);
}
}
} else {
// no settings panel, go straight to settings
mSettingsButton.setVisibility(View.VISIBLE);
mSettingsButton.setImageResource(R.drawable.ic_notify_settings);
}
}
if (mHasFlipSettings) {
mNotificationButton = (ImageView) mStatusBarWindow.findViewById(
R.id.notification_button);
if (mNotificationButton != null) {
mNotificationButton.setOnClickListener(mNotificationButtonListener);
}
}
mHeaderFlipper = new FlipperButton(mNotificationPanelHeader
.findViewById(R.id.settings_button_holder));
ViewStub flipStub = (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_flip_stub);
mKeyguardFlipper = new FlipperButton(flipStub.inflate());
if (!mNotificationPanelIsFullScreenWidth) {
mNotificationPanel.setSystemUiVisibility(
@@ -735,6 +713,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
// Quick Settings (where available, some restrictions apply)
mNotificationPadding = mContext.getResources()
.getDimensionPixelSize(R.dimen.notification_side_padding);
if (mHasSettingsPanel) {
// first, figure out where quick settings should be inflated
final View settings_stub;
@@ -803,6 +783,87 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
return mStatusBarView;
}
public boolean onSettingsEvent(MotionEvent event) {
if (mSettingsTracker != null) {
mSettingsTracker.addMovement(event);
}
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mSettingsTracker = VelocityTracker.obtain();
mSettingsDownY = event.getY();
mSettingsCancelled = false;
mSettingsClosing = mFlipSettingsView.getVisibility() == View.VISIBLE;
mFlipSettingsView.setVisibility(View.VISIBLE);
mStackScroller.setVisibility(View.VISIBLE);
positionSettings(0);
if (!mSettingsClosing) {
mFlipSettingsView.setTranslationY(-mNotificationPanel.getMeasuredHeight());
}
dispatchSettingsEvent(event);
} else if (mSettingsTracker != null && (event.getAction() == MotionEvent.ACTION_UP
|| event.getAction() == MotionEvent.ACTION_CANCEL)) {
final float dy = event.getY() - mSettingsDownY;
final FlipperButton flipper = mOnKeyguard ? mKeyguardFlipper : mHeaderFlipper;
final boolean inButton = flipper.inHolderBounds(event);
final int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
final boolean qsTap = mSettingsClosing && Math.abs(dy) < slop;
if (!qsTap && !inButton) {
mSettingsTracker.computeCurrentVelocity(1000);
final float vy = mSettingsTracker.getYVelocity();
if (dy <= slop || vy <= 0) {
flipToNotifications();
} else {
flipToSettings();
}
}
mSettingsTracker.recycle();
mSettingsTracker = null;
dispatchSettingsEvent(event);
} else if (mSettingsTracker != null && event.getAction() == MotionEvent.ACTION_MOVE) {
final float dy = event.getY() - mSettingsDownY;
positionSettings(dy);
if (mSettingsClosing) {
final boolean qsTap =
Math.abs(dy) < ViewConfiguration.get(mContext).getScaledTouchSlop();
if (!mSettingsCancelled && !qsTap) {
MotionEvent cancelEvent = MotionEvent.obtainNoHistory(event);
cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
dispatchSettingsEvent(cancelEvent);
mSettingsCancelled = true;
}
} else {
dispatchSettingsEvent(event);
}
}
return true;
}
private void dispatchSettingsEvent(MotionEvent event) {
final View target = mSettingsClosing ? mFlipSettingsView : mNotificationPanelHeader;
final int[] targetLoc = new int[2];
target.getLocationInWindow(targetLoc);
final int[] panelLoc = new int[2];
mNotificationPanel.getLocationInWindow(panelLoc);
final int dx = targetLoc[0] - panelLoc[0];
final int dy = targetLoc[1] - panelLoc[1];
event.offsetLocation(-dx, -dy);
target.dispatchTouchEvent(event);
}
private void positionSettings(float dy) {
final int h = mFlipSettingsView.getMeasuredHeight();
final int ph = mNotificationPanel.getMeasuredHeight();
if (mSettingsClosing) {
dy = Math.min(Math.max(-ph, dy), 0);
mFlipSettingsView.setTranslationY(dy);
mStackScroller.setTranslationY(ph + dy);
} else {
dy = Math.min(Math.max(0, dy), ph);
mFlipSettingsView.setTranslationY(-h + dy - mNotificationPadding * 2);
mStackScroller.setTranslationY(dy);
}
}
private void startKeyguard() {
KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
@@ -1163,17 +1224,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
((ImageView)mClearButton).setImageResource(R.drawable.ic_notify_clear);
}
if (mSettingsButton != null) {
// Force asset reloading
mSettingsButton.setImageDrawable(null);
mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
}
if (mNotificationButton != null) {
// Force asset reloading
mNotificationButton.setImageDrawable(null);
mNotificationButton.setImageResource(R.drawable.ic_notifications);
}
mHeaderFlipper.refreshLayout();
mKeyguardFlipper.refreshLayout();
refreshAllStatusBarIcons();
}
@@ -1228,9 +1280,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
}
if (mSettingsButton != null) {
mSettingsButton.setEnabled(isDeviceProvisioned());
}
mHeaderFlipper.provisionCheck(provisioned);
mKeyguardFlipper.provisionCheck(provisioned);
}
@Override
@@ -1647,6 +1698,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
mStatusBarWindow.cancelExpandHelper();
mStatusBarView.collapseAllPanels(true);
if (isFlippedToSettings()) {
flipToNotifications();
}
}
}
@@ -1694,8 +1748,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
final int FLIP_DURATION_IN = 225;
final int FLIP_DURATION = (FLIP_DURATION_IN + FLIP_DURATION_OUT);
Animator mScrollViewAnim, mFlipSettingsViewAnim, mNotificationButtonAnim,
mSettingsButtonAnim, mClearButtonAnim;
Animator mScrollViewAnim, mFlipSettingsViewAnim, mClearButtonAnim;
@Override
public void animateExpandNotificationsPanel() {
@@ -1715,33 +1768,29 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
public void flipToNotifications() {
if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
if (mScrollViewAnim != null) mScrollViewAnim.cancel();
if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
mHeaderFlipper.cancel();
mKeyguardFlipper.cancel();
if (mClearButtonAnim != null) mClearButtonAnim.cancel();
mStackScroller.setVisibility(View.VISIBLE);
final int h = mNotificationPanel.getMeasuredHeight();
final float settingsY = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : 0;
final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : h;
mScrollViewAnim = start(
startDelay(FLIP_DURATION_OUT,
startDelay(0,
interpolator(mDecelerateInterpolator,
ObjectAnimator.ofFloat(mStackScroller, View.SCALE_X, 0f, 1f)
.setDuration(FLIP_DURATION_IN)
ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, 0)
.setDuration(FLIP_DURATION)
)));
mFlipSettingsViewAnim = start(
setVisibilityWhenDone(
interpolator(mAccelerateInterpolator,
ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 1f, 0f)
interpolator(mDecelerateInterpolator,
ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y, settingsY, -h)
)
.setDuration(FLIP_DURATION_OUT),
mFlipSettingsView, View.INVISIBLE));
mNotificationButtonAnim = start(
setVisibilityWhenDone(
ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f)
.setDuration(FLIP_DURATION),
mNotificationButton, View.INVISIBLE));
mSettingsButton.setVisibility(View.VISIBLE);
mSettingsButtonAnim = start(
ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f)
.setDuration(FLIP_DURATION));
mFlipSettingsView, View.INVISIBLE));
mHeaderFlipper.flipToNotifications();
mKeyguardFlipper.flipToNotifications();
mClearButton.setVisibility(View.VISIBLE);
mClearButton.setAlpha(0f);
setAreThereNotifications(); // this will show/hide the button as necessary
@@ -1767,7 +1816,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
if (mHasFlipSettings) {
mNotificationPanel.expand();
if (mFlipSettingsView.getVisibility() != View.VISIBLE) {
if (mFlipSettingsView.getVisibility() != View.VISIBLE
|| mFlipSettingsView.getTranslationY() < 0) {
flipToSettings();
}
} else if (mSettingsPanel != null) {
@@ -1777,23 +1827,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
if (false) postStartTracing();
}
public void switchToSettings() {
// Settings are not available in setup
if (!mUserSetup) return;
mFlipSettingsView.setScaleX(1f);
mFlipSettingsView.setVisibility(View.VISIBLE);
mSettingsButton.setVisibility(View.GONE);
mStackScroller.setVisibility(View.GONE);
mStackScroller.setScaleX(0f);
mNotificationButton.setVisibility(View.VISIBLE);
mNotificationButton.setAlpha(1f);
mClearButton.setVisibility(View.GONE);
if (mOnFlipRunnable != null) {
mOnFlipRunnable.run();
}
}
public boolean isFlippedToSettings() {
if (mFlipSettingsView != null) {
return mFlipSettingsView.getVisibility() == View.VISIBLE;
@@ -1807,34 +1840,29 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
if (mScrollViewAnim != null) mScrollViewAnim.cancel();
if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
mHeaderFlipper.cancel();
mKeyguardFlipper.cancel();
if (mClearButtonAnim != null) mClearButtonAnim.cancel();
mFlipSettingsView.setVisibility(View.VISIBLE);
mFlipSettingsView.setScaleX(0f);
final int h = mNotificationPanel.getMeasuredHeight();
final float settingsY = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : -h;
final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : 0;
mFlipSettingsViewAnim = start(
startDelay(FLIP_DURATION_OUT,
interpolator(mDecelerateInterpolator,
ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 0f, 1f)
.setDuration(FLIP_DURATION_IN)
)));
startDelay(0,
interpolator(mDecelerateInterpolator,
ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y, settingsY, 0f)
.setDuration(FLIP_DURATION)
)));
mScrollViewAnim = start(
setVisibilityWhenDone(
interpolator(mAccelerateInterpolator,
ObjectAnimator.ofFloat(mStackScroller, View.SCALE_X, 1f, 0f)
interpolator(mDecelerateInterpolator,
ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, h)
)
.setDuration(FLIP_DURATION_OUT),
mStackScroller, View.INVISIBLE));
mSettingsButtonAnim = start(
setVisibilityWhenDone(
ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
.setDuration(FLIP_DURATION),
mStackScroller, View.INVISIBLE));
mNotificationButton.setVisibility(View.VISIBLE);
mNotificationButtonAnim = start(
ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
.setDuration(FLIP_DURATION));
mHeaderFlipper.flipToSettings();
mKeyguardFlipper.flipToSettings();
mClearButtonAnim = start(
setVisibilityWhenDone(
ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f)
@@ -1883,18 +1911,16 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
// reset things to their proper state
if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
if (mScrollViewAnim != null) mScrollViewAnim.cancel();
if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
if (mClearButtonAnim != null) mClearButtonAnim.cancel();
mStackScroller.setScaleX(1f);
mStackScroller.setVisibility(View.VISIBLE);
mSettingsButton.setAlpha(1f);
mSettingsButton.setVisibility(View.VISIBLE);
mNotificationPanel.setVisibility(View.GONE);
mFlipSettingsView.setVisibility(View.GONE);
mNotificationButton.setVisibility(View.GONE);
setAreThereNotifications(); // show the clear button
mHeaderFlipper.reset();
mKeyguardFlipper.reset();
}
mExpandedVisible = false;
@@ -2947,15 +2973,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
mKeyguardStatusView.setVisibility(View.VISIBLE);
mNotificationPanelHeader.setVisibility(View.GONE);
if (mKeyguardSettingsFlipButton == null) {
ViewStub flipStub = (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_flip_stub);
mKeyguardSettingsFlipButton = flipStub.inflate();
installSettingsButton(mKeyguardSettingsFlipButton);
}
mKeyguardSettingsFlipButton.setVisibility(View.VISIBLE);
mKeyguardSettingsFlipButton.findViewById(R.id.settings_button).setVisibility(View.VISIBLE);
mKeyguardSettingsFlipButton.findViewById(R.id.notification_button)
.setVisibility(View.INVISIBLE);
mKeyguardFlipper.setVisibility(View.VISIBLE);
mSettingsContainer.setKeyguardShowing(true);
updateRowStates();
}
@@ -2963,9 +2983,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
mOnKeyguard = false;
mKeyguardStatusView.setVisibility(View.GONE);
mNotificationPanelHeader.setVisibility(View.VISIBLE);
if (mKeyguardSettingsFlipButton != null) {
mKeyguardSettingsFlipButton.setVisibility(View.GONE);
}
mKeyguardFlipper.setVisibility(View.GONE);
mSettingsContainer.setKeyguardShowing(false);
updateRowStates();
instantCollapseNotificationPanel();
}
@@ -3030,39 +3050,112 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
}
private void installSettingsButton(View parent) {
final ImageView settingsButton =
(ImageView) mStatusBarWindow.findViewById(R.id.settings_button);
final ImageView notificationButton =
(ImageView) mStatusBarWindow.findViewById(R.id.notification_button);
if (settingsButton != null) {
settingsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animateExpandSettingsPanel();
v.setVisibility(View.INVISIBLE);
notificationButton.setVisibility(View.VISIBLE);
public static boolean inBounds(View view, MotionEvent event, boolean orAbove) {
final int[] location = new int[2];
view.getLocationInWindow(location);
final int rx = (int) event.getRawX();
final int ry = (int) event.getRawY();
return rx >= location[0] && rx <= location[0] + view.getMeasuredWidth()
&& (orAbove || ry >= location[1]) && ry <= location[1] + view.getMeasuredHeight();
}
private final class FlipperButton {
private final View mHolder;
private ImageView mSettingsButton, mNotificationButton;
private Animator mSettingsButtonAnim, mNotificationButtonAnim;
public FlipperButton(View holder) {
mHolder = holder;
mSettingsButton = (ImageView) holder.findViewById(R.id.settings_button);
if (mSettingsButton != null) {
mSettingsButton.setOnClickListener(mSettingsButtonListener);
if (mHasSettingsPanel) {
// the settings panel is hiding behind this button
mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
mSettingsButton.setVisibility(View.VISIBLE);
} else {
// no settings panel, go straight to settings
mSettingsButton.setVisibility(View.VISIBLE);
mSettingsButton.setImageResource(R.drawable.ic_notify_settings);
}
}
if (mHasFlipSettings) {
mNotificationButton = (ImageView) holder.findViewById(R.id.notification_button);
if (mNotificationButton != null) {
mNotificationButton.setOnClickListener(mNotificationButtonListener);
}
});
settingsButton.setVisibility(View.VISIBLE);
if (mHasSettingsPanel) {
// the settings panel is hiding behind this button
settingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
} else {
// no settings panel, go straight to settings
settingsButton.setImageResource(R.drawable.ic_notify_settings);
}
}
if (notificationButton != null) {
notificationButton.setVisibility(View.INVISIBLE);
notificationButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
flipToNotifications();
v.setVisibility(View.INVISIBLE);
settingsButton.setVisibility(View.VISIBLE);
}
});
public boolean inHolderBounds(MotionEvent event) {
return inBounds(mHolder, event, false);
}
public void provisionCheck(boolean provisioned) {
if (mSettingsButton != null) {
mSettingsButton.setEnabled(provisioned);
}
}
public void userSetup(boolean userSetup) {
if (mSettingsButton != null && mHasFlipSettings) {
mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE);
}
}
public void reset() {
cancel();
mSettingsButton.setVisibility(View.VISIBLE);
mNotificationButton.setVisibility(View.GONE);
}
public void refreshLayout() {
if (mSettingsButton != null) {
// Force asset reloading
mSettingsButton.setImageDrawable(null);
mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
}
if (mNotificationButton != null) {
// Force asset reloading
mNotificationButton.setImageDrawable(null);
mNotificationButton.setImageResource(R.drawable.ic_notifications);
}
}
public void flipToSettings() {
mSettingsButtonAnim = start(
setVisibilityWhenDone(
ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
.setDuration(FLIP_DURATION),
mStackScroller, View.INVISIBLE));
mNotificationButton.setVisibility(View.VISIBLE);
mNotificationButtonAnim = start(
ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
.setDuration(FLIP_DURATION));
}
public void flipToNotifications() {
mNotificationButtonAnim = start(
setVisibilityWhenDone(
ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f)
.setDuration(FLIP_DURATION),
mNotificationButton, View.INVISIBLE));
mSettingsButton.setVisibility(View.VISIBLE);
mSettingsButtonAnim = start(
ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f)
.setDuration(FLIP_DURATION));
}
public void cancel() {
if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
}
public void setVisibility(int vis) {
mHolder.setVisibility(vis);
}
}
}

View File

@@ -19,7 +19,13 @@ package com.android.systemui.statusbar.phone;
import android.animation.LayoutTransition;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -31,30 +37,58 @@ import com.android.systemui.R;
*/
class QuickSettingsContainerView extends FrameLayout {
private static boolean sShowScrim = true;
private final Context mContext;
// The number of columns in the QuickSettings grid
private int mNumColumns;
private boolean mKeyguardShowing;
private int mMaxRows;
private int mMaxRowsOnKeyguard;
// The gap between tiles in the QuickSettings grid
private float mCellGap;
private ScrimView mScrim;
public QuickSettingsContainerView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
updateResources();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mScrim = new ScrimView(mContext);
addView(mScrim);
mScrim.setAlpha(sShowScrim ? 1 : 0);
// TODO: Setup the layout transitions
LayoutTransition transitions = getLayoutTransition();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mScrim.getAlpha() == 1) {
mScrim.animate().alpha(0).setDuration(1000).start();
sShowScrim = false;
}
return super.onTouchEvent(event);
}
void updateResources() {
Resources r = getContext().getResources();
mCellGap = r.getDimension(R.dimen.quick_settings_cell_gap);
mNumColumns = r.getInteger(R.integer.quick_settings_num_columns);
mMaxRows = r.getInteger(R.integer.quick_settings_max_rows);
mMaxRowsOnKeyguard = r.getInteger(R.integer.quick_settings_max_rows_keyguard);
requestLayout();
}
void setKeyguardShowing(boolean showing) {
mKeyguardShowing = showing;
requestLayout();
}
@@ -71,10 +105,18 @@ class QuickSettingsContainerView extends FrameLayout {
final int N = getChildCount();
int cellHeight = 0;
int cursor = 0;
int maxRows = mKeyguardShowing ? mMaxRowsOnKeyguard : mMaxRows;
for (int i = 0; i < N; ++i) {
if (getChildAt(i).equals(mScrim)) {
continue;
}
// Update the child's width
QuickSettingsTileView v = (QuickSettingsTileView) getChildAt(i);
if (v.getVisibility() != View.GONE) {
int row = (int) (cursor / mNumColumns);
if (row >= maxRows) continue;
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
int colSpan = v.getColumnSpan();
lp.width = (int) ((colSpan * cellWidth) + (colSpan - 1) * mCellGap);
@@ -102,6 +144,7 @@ class QuickSettingsContainerView extends FrameLayout {
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
mScrim.bringToFront();
final int N = getChildCount();
final boolean isLayoutRtl = isLayoutRtl();
final int width = getWidth();
@@ -109,8 +152,18 @@ class QuickSettingsContainerView extends FrameLayout {
int x = getPaddingStart();
int y = getPaddingTop();
int cursor = 0;
int maxRows = mKeyguardShowing ? mMaxRowsOnKeyguard : mMaxRows;
for (int i = 0; i < N; ++i) {
if (getChildAt(i).equals(mScrim)) {
int w = right - left - getPaddingLeft() - getPaddingRight();
int h = bottom - top - getPaddingTop() - getPaddingBottom();
mScrim.measure(
MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY));
mScrim.layout(getPaddingLeft(), getPaddingTop(), right, bottom);
continue;
}
QuickSettingsTileView child = (QuickSettingsTileView) getChildAt(i);
ViewGroup.LayoutParams lp = child.getLayoutParams();
if (child.getVisibility() != GONE) {
@@ -121,6 +174,7 @@ class QuickSettingsContainerView extends FrameLayout {
final int childHeight = lp.height;
int row = (int) (cursor / mNumColumns);
if (row >= maxRows) continue;
// Push the item to the next row if it can't fit on this one
if ((col + colSpan) > mNumColumns) {
@@ -150,4 +204,87 @@ class QuickSettingsContainerView extends FrameLayout {
}
}
}
private static final class ScrimView extends View {
private static final int COLOR = 0xaf4285f4;
private final Paint mLinePaint;
private final int mStrokeWidth;
private final Rect mTmp = new Rect();
private final Paint mTextPaint;
private final int mTextSize;
public ScrimView(Context context) {
super(context);
setFocusable(false);
final Resources res = context.getResources();
mStrokeWidth = res.getDimensionPixelSize(R.dimen.quick_settings_tmp_scrim_stroke_width);
mTextSize = res.getDimensionPixelSize(R.dimen.quick_settings_tmp_scrim_text_size);
mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mLinePaint.setColor(COLOR);
mLinePaint.setStrokeWidth(mStrokeWidth);
mLinePaint.setStrokeJoin(Paint.Join.ROUND);
mLinePaint.setStrokeCap(Paint.Cap.ROUND);
mLinePaint.setStyle(Paint.Style.STROKE);
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(COLOR);
mTextPaint.setTextSize(mTextSize);
mTextPaint.setTypeface(Typeface.create("sans-serif-condensed", Typeface.BOLD));
}
@Override
protected void onDraw(Canvas canvas) {
final int w = getMeasuredWidth();
final int h = getMeasuredHeight();
final int f = mStrokeWidth * 3 / 4;
canvas.drawPath(line(f, h / 2, w - f, h / 2), mLinePaint);
canvas.drawPath(line(w / 2, f, w / 2, h - f), mLinePaint);
final int s = mStrokeWidth;
mTextPaint.setTextAlign(Paint.Align.RIGHT);
canvas.drawText("FUTURE", w / 2 - s, h / 2 - s, mTextPaint);
mTextPaint.setTextAlign(Paint.Align.LEFT);
canvas.drawText("SITE OF", w / 2 + s, h / 2 - s , mTextPaint);
mTextPaint.setTextAlign(Paint.Align.RIGHT);
drawUnder(canvas, "QUANTUM", w / 2 - s, h / 2 + s);
mTextPaint.setTextAlign(Paint.Align.LEFT);
drawUnder(canvas, "SETTINGS", w / 2 + s, h / 2 + s);
}
private void drawUnder(Canvas c, String text, float x, float y) {
if (mTmp.isEmpty()) {
mTextPaint.getTextBounds(text, 0, text.length(), mTmp);
}
c.drawText(text, x, y + mTmp.height() * .85f, mTextPaint);
}
private Path line(float x1, float y1, float x2, float y2) {
final int a = mStrokeWidth * 2;
final Path p = new Path();
p.moveTo(x1, y1);
p.lineTo(x2, y2);
if (y1 == y2) {
p.moveTo(x1 + a, y1 + a);
p.lineTo(x1, y1);
p.lineTo(x1 + a, y1 - a);
p.moveTo(x2 - a, y2 - a);
p.lineTo(x2, y2);
p.lineTo(x2 - a, y2 + a);
}
if (x1 == x2) {
p.moveTo(x1 - a, y1 + a);
p.lineTo(x1, y1);
p.lineTo(x1 + a, y1 + a);
p.moveTo(x2 - a, y2 - a);
p.lineTo(x2, y2);
p.lineTo(x2 + a, y2 - a);
}
return p;
}
}
}