Merge "Changed the swipe up search affordance" into lmp-dev
This commit is contained in:
@ -17,16 +17,8 @@
|
||||
*/
|
||||
-->
|
||||
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shareInterpolator="false" android:zAdjustment="top">
|
||||
|
||||
<alpha android:fromAlpha="0" android:toAlpha="1.0"
|
||||
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
|
||||
android:interpolator="@android:interpolator/decelerate_cubic"
|
||||
android:duration="300"/>
|
||||
|
||||
<translate android:fromYDelta="100%" android:toYDelta="0"
|
||||
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
|
||||
android:interpolator="@android:interpolator/decelerate_cubic"
|
||||
android:duration="300" />
|
||||
</set>
|
||||
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fromAlpha="0" android:toAlpha="1.0"
|
||||
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
|
||||
android:interpolator="@android:interpolator/decelerate_cubic"
|
||||
android:duration="300"/>
|
@ -1,21 +0,0 @@
|
||||
<?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
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/search_panel_card_color" />
|
||||
<corners android:radius="@dimen/notification_material_rounded_rect_radius" />
|
||||
</shape>
|
@ -30,17 +30,14 @@
|
||||
android:id="@+id/search_panel_scrim"
|
||||
android:background="@drawable/search_panel_scrim" />
|
||||
|
||||
<FrameLayout
|
||||
style="@style/SearchPanelCard"
|
||||
android:id="@+id/search_panel_card"
|
||||
android:background="@drawable/search_panel_card_bg"
|
||||
android:elevation="12dp">
|
||||
<com.android.systemui.SearchPanelCircleView
|
||||
style="@style/SearchPanelCircle"
|
||||
android:id="@+id/search_panel_circle">
|
||||
|
||||
<ImageView
|
||||
style="@style/SearchPanelLogo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/search_logo" />
|
||||
</FrameLayout>
|
||||
</com.android.systemui.SearchPanelCircleView>
|
||||
|
||||
</com.android.systemui.SearchPanelView>
|
||||
|
@ -19,18 +19,6 @@
|
||||
<item name="android:layout_width">360dp</item>
|
||||
</style>
|
||||
|
||||
<style name="SearchPanelCard">
|
||||
<item name="android:layout_width">@dimen/search_panel_card_height</item>
|
||||
<item name="android:layout_height">match_parent</item>
|
||||
<item name="android:layout_marginTop">16dp</item>
|
||||
<item name="android:layout_marginBottom">16dp</item>
|
||||
<item name="android:layout_gravity">right</item>
|
||||
</style>
|
||||
|
||||
<style name="SearchPanelLogo">
|
||||
<item name="android:layout_gravity">top|left</item>
|
||||
</style>
|
||||
|
||||
<style name="SearchPanelScrim">
|
||||
<item name="android:layout_width">@dimen/search_panel_scrim_height</item>
|
||||
<item name="android:layout_height">match_parent</item>
|
||||
|
@ -19,16 +19,6 @@
|
||||
<item name="android:layout_width">480dp</item>
|
||||
</style>
|
||||
|
||||
<style name="SearchPanelCard">
|
||||
<item name="android:layout_width">550dp</item>
|
||||
<item name="android:layout_height">@dimen/search_panel_card_height</item>
|
||||
<item name="android:layout_gravity">center_horizontal|bottom</item>
|
||||
</style>
|
||||
|
||||
<style name="SearchPanelLogo">
|
||||
<item name="android:layout_gravity">top|center_horizontal</item>
|
||||
</style>
|
||||
|
||||
<style name="SearchPanelScrim">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">@dimen/search_panel_scrim_height</item>
|
||||
|
@ -109,7 +109,8 @@
|
||||
<color name="notification_guts_text_color">#b2FFFFFF</color>
|
||||
<color name="notification_guts_btn_color">#FFFFFFFF</color>
|
||||
|
||||
<color name="search_panel_card_color">#ffffff</color>
|
||||
<color name="search_panel_circle_color">#ffffff</color>
|
||||
<color name="search_panel_ripple_color">#ffbbbbbb</color>
|
||||
|
||||
<color name="keyguard_user_switcher_background_gradient_color">#77000000</color>
|
||||
<color name="doze_small_icon_background_color">#ff434343</color>
|
||||
|
@ -434,16 +434,21 @@
|
||||
from Keyguard. -->
|
||||
<dimen name="go_to_full_shade_appearing_translation">200dp</dimen>
|
||||
|
||||
<!-- The height of the search panel card. -->
|
||||
<dimen name="search_panel_card_height">300dp</dimen>
|
||||
<!-- The diameter of the search panel circle. -->
|
||||
<dimen name="search_panel_circle_size">88dp</dimen>
|
||||
|
||||
<!-- The height of the scrim behind the search panel card. -->
|
||||
<!-- The margin to the edge of the screen from where the circle starts to appear -->
|
||||
<dimen name="search_panel_circle_base_margin">80dp</dimen>
|
||||
|
||||
<!-- The amount the circle translates when appearing -->
|
||||
<dimen name="search_panel_circle_travel_distance">80dp</dimen>
|
||||
|
||||
<!-- The elevation of the search panel circle -->
|
||||
<dimen name="search_panel_circle_elevation">12dp</dimen>
|
||||
|
||||
<!-- The height of the scrim behind the search panel circle. -->
|
||||
<dimen name="search_panel_scrim_height">250dp</dimen>
|
||||
|
||||
<!-- How much from the bottom of the screen the card should peek in when activating the search
|
||||
panel -->
|
||||
<dimen name="search_card_peek_height">100dp</dimen>
|
||||
|
||||
<!-- How far the user needs to drag up to invoke search. -->
|
||||
<dimen name="search_panel_threshold">100dp</dimen>
|
||||
|
||||
|
@ -239,16 +239,9 @@
|
||||
<item name="android:textColor">#60000000</item>
|
||||
</style>
|
||||
|
||||
<style name="SearchPanelCard">
|
||||
<style name="SearchPanelCircle">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">@dimen/search_panel_card_height</item>
|
||||
<item name="android:layout_marginStart">8dp</item>
|
||||
<item name="android:layout_marginEnd">8dp</item>
|
||||
<item name="android:layout_gravity">bottom</item>
|
||||
</style>
|
||||
|
||||
<style name="SearchPanelLogo">
|
||||
<item name="android:layout_gravity">top|center_horizontal</item>
|
||||
<item name="android:layout_height">match_parent</item>
|
||||
</style>
|
||||
|
||||
<style name="SearchPanelScrim">
|
||||
|
@ -0,0 +1,592 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
package com.android.systemui;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import com.android.systemui.statusbar.phone.PhoneStatusBar;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class SearchPanelCircleView extends FrameLayout {
|
||||
|
||||
private final int mCircleMinSize;
|
||||
private final int mBaseMargin;
|
||||
private final int mStaticOffset;
|
||||
private final Paint mBackgroundPaint = new Paint();
|
||||
private final Paint mRipplePaint = new Paint();
|
||||
private final Rect mCircleRect = new Rect();
|
||||
private final Rect mStaticRect = new Rect();
|
||||
private final Interpolator mFastOutSlowInInterpolator;
|
||||
private final Interpolator mAppearInterpolator;
|
||||
private final Interpolator mDisappearInterpolator;
|
||||
|
||||
private boolean mClipToOutline;
|
||||
private final int mMaxElevation;
|
||||
private boolean mAnimatingOut;
|
||||
private float mOutlineAlpha;
|
||||
private float mOffset;
|
||||
private float mCircleSize;
|
||||
private boolean mHorizontal;
|
||||
private boolean mCircleHidden;
|
||||
private ImageView mLogo;
|
||||
private boolean mDraggedFarEnough;
|
||||
private boolean mOffsetAnimatingIn;
|
||||
private float mCircleAnimationEndValue;
|
||||
private ArrayList<Ripple> mRipples = new ArrayList<Ripple>();
|
||||
|
||||
private ValueAnimator mOffsetAnimator;
|
||||
private ValueAnimator mCircleAnimator;
|
||||
private ValueAnimator mFadeOutAnimator;
|
||||
private ValueAnimator.AnimatorUpdateListener mCircleUpdateListener
|
||||
= new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
applyCircleSize((float) animation.getAnimatedValue());
|
||||
updateElevation();
|
||||
}
|
||||
};
|
||||
private AnimatorListenerAdapter mClearAnimatorListener = new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mCircleAnimator = null;
|
||||
}
|
||||
};
|
||||
private ValueAnimator.AnimatorUpdateListener mOffsetUpdateListener
|
||||
= new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
setOffset((float) animation.getAnimatedValue());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public SearchPanelCircleView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public SearchPanelCircleView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public SearchPanelCircleView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public SearchPanelCircleView(Context context, AttributeSet attrs, int defStyleAttr,
|
||||
int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
setOutlineProvider(new ViewOutlineProvider() {
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline) {
|
||||
if (mCircleSize > 0.0f) {
|
||||
outline.setOval(mCircleRect);
|
||||
} else {
|
||||
outline.setEmpty();
|
||||
}
|
||||
outline.setAlpha(mOutlineAlpha);
|
||||
}
|
||||
});
|
||||
setWillNotDraw(false);
|
||||
mCircleMinSize = context.getResources().getDimensionPixelSize(
|
||||
R.dimen.search_panel_circle_size);
|
||||
mBaseMargin = context.getResources().getDimensionPixelSize(
|
||||
R.dimen.search_panel_circle_base_margin);
|
||||
mStaticOffset = context.getResources().getDimensionPixelSize(
|
||||
R.dimen.search_panel_circle_travel_distance);
|
||||
mMaxElevation = context.getResources().getDimensionPixelSize(
|
||||
R.dimen.search_panel_circle_elevation);
|
||||
mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
|
||||
android.R.interpolator.linear_out_slow_in);
|
||||
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(mContext,
|
||||
android.R.interpolator.fast_out_slow_in);
|
||||
mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
|
||||
android.R.interpolator.fast_out_linear_in);
|
||||
mBackgroundPaint.setAntiAlias(true);
|
||||
mBackgroundPaint.setColor(getResources().getColor(R.color.search_panel_circle_color));
|
||||
mRipplePaint.setColor(getResources().getColor(R.color.search_panel_ripple_color));
|
||||
mRipplePaint.setAntiAlias(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
drawBackground(canvas);
|
||||
drawRipples(canvas);
|
||||
}
|
||||
|
||||
private void drawRipples(Canvas canvas) {
|
||||
for (int i = 0; i < mRipples.size(); i++) {
|
||||
Ripple ripple = mRipples.get(i);
|
||||
ripple.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawBackground(Canvas canvas) {
|
||||
canvas.drawCircle(mCircleRect.centerX(), mCircleRect.centerY(), mCircleSize / 2,
|
||||
mBackgroundPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mLogo = (ImageView) findViewById(R.id.search_logo);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
mLogo.layout(0, 0, mLogo.getMeasuredWidth(), mLogo.getMeasuredHeight());
|
||||
if (changed) {
|
||||
updateCircleRect(mStaticRect, mStaticOffset, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCircleSize(float circleSize) {
|
||||
setCircleSize(circleSize, false, null, 0, null);
|
||||
}
|
||||
|
||||
public void setCircleSize(float circleSize, boolean animated, final Runnable endRunnable,
|
||||
int startDelay, Interpolator interpolator) {
|
||||
boolean isAnimating = mCircleAnimator != null;
|
||||
boolean animationPending = isAnimating && !mCircleAnimator.isRunning();
|
||||
boolean animatingOut = isAnimating && mCircleAnimationEndValue == 0;
|
||||
if (animated || animationPending || animatingOut) {
|
||||
if (isAnimating) {
|
||||
if (circleSize == mCircleAnimationEndValue) {
|
||||
return;
|
||||
}
|
||||
mCircleAnimator.cancel();
|
||||
}
|
||||
mCircleAnimator = ValueAnimator.ofFloat(mCircleSize, circleSize);
|
||||
mCircleAnimator.addUpdateListener(mCircleUpdateListener);
|
||||
mCircleAnimator.addListener(mClearAnimatorListener);
|
||||
mCircleAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (endRunnable != null) {
|
||||
endRunnable.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
Interpolator desiredInterpolator = interpolator != null ? interpolator
|
||||
: circleSize == 0 ? mDisappearInterpolator : mAppearInterpolator;
|
||||
mCircleAnimator.setInterpolator(desiredInterpolator);
|
||||
mCircleAnimator.setDuration(300);
|
||||
mCircleAnimator.setStartDelay(startDelay);
|
||||
mCircleAnimator.start();
|
||||
mCircleAnimationEndValue = circleSize;
|
||||
} else {
|
||||
if (isAnimating) {
|
||||
float diff = circleSize - mCircleAnimationEndValue;
|
||||
PropertyValuesHolder[] values = mCircleAnimator.getValues();
|
||||
values[0].setFloatValues(diff, circleSize);
|
||||
mCircleAnimator.setCurrentPlayTime(mCircleAnimator.getCurrentPlayTime());
|
||||
mCircleAnimationEndValue = circleSize;
|
||||
} else {
|
||||
applyCircleSize(circleSize);
|
||||
updateElevation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applyCircleSize(float circleSize) {
|
||||
mCircleSize = circleSize;
|
||||
updateLayout();
|
||||
}
|
||||
|
||||
private void updateElevation() {
|
||||
float t = (mStaticOffset - mOffset) / (float) mStaticOffset;
|
||||
t = 1.0f - Math.max(t, 0.0f);
|
||||
float offset = t * mMaxElevation;
|
||||
setElevation(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the offset to the edge of the screen. By default this not not animated.
|
||||
*
|
||||
* @param offset The offset to apply.
|
||||
*/
|
||||
public void setOffset(float offset) {
|
||||
setOffset(offset, false, 0, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the offset to the edge of the screen.
|
||||
*
|
||||
* @param offset The offset to apply.
|
||||
* @param animate Whether an animation should be performed.
|
||||
* @param startDelay The desired start delay if animated.
|
||||
* @param interpolator The desired interpolator if animated. If null,
|
||||
* a default interpolator will be taken designed for appearing or
|
||||
* disappearing.
|
||||
* @param endRunnable The end runnable which should be executed when the animation is finished.
|
||||
*/
|
||||
private void setOffset(float offset, boolean animate, int startDelay,
|
||||
Interpolator interpolator, final Runnable endRunnable) {
|
||||
if (!animate) {
|
||||
mOffset = offset;
|
||||
updateLayout();
|
||||
if (endRunnable != null) {
|
||||
endRunnable.run();
|
||||
}
|
||||
} else {
|
||||
if (mOffsetAnimator != null) {
|
||||
mOffsetAnimator.removeAllListeners();
|
||||
mOffsetAnimator.cancel();
|
||||
}
|
||||
mOffsetAnimator = ValueAnimator.ofFloat(mOffset, offset);
|
||||
mOffsetAnimator.addUpdateListener(mOffsetUpdateListener);
|
||||
mOffsetAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mOffsetAnimator = null;
|
||||
if (endRunnable != null) {
|
||||
endRunnable.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
Interpolator desiredInterpolator = interpolator != null ?
|
||||
interpolator : offset == 0 ? mDisappearInterpolator : mAppearInterpolator;
|
||||
mOffsetAnimator.setInterpolator(desiredInterpolator);
|
||||
mOffsetAnimator.setStartDelay(startDelay);
|
||||
mOffsetAnimator.setDuration(300);
|
||||
mOffsetAnimator.start();
|
||||
mOffsetAnimatingIn = offset != 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateLayout() {
|
||||
updateCircleRect();
|
||||
updateLogo();
|
||||
invalidateOutline();
|
||||
invalidate();
|
||||
updateClipping();
|
||||
}
|
||||
|
||||
private void updateClipping() {
|
||||
boolean clip = mCircleSize < mCircleMinSize || !mRipples.isEmpty();
|
||||
if (clip != mClipToOutline) {
|
||||
setClipToOutline(clip);
|
||||
mClipToOutline = clip;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateLogo() {
|
||||
boolean exitAnimationRunning = mFadeOutAnimator != null;
|
||||
Rect rect = exitAnimationRunning ? mCircleRect : mStaticRect;
|
||||
float translationX = (rect.left + rect.right) / 2.0f - mLogo.getWidth() / 2.0f;
|
||||
float translationY = (rect.top + rect.bottom) / 2.0f - mLogo.getHeight() / 2.0f;
|
||||
float t = (mStaticOffset - mOffset) / (float) mStaticOffset;
|
||||
if (!exitAnimationRunning) {
|
||||
if (mHorizontal) {
|
||||
translationX += t * mStaticOffset * 0.3f;
|
||||
} else {
|
||||
translationY += t * mStaticOffset * 0.3f;
|
||||
}
|
||||
float alpha = 1.0f-t;
|
||||
alpha = Math.max((alpha - 0.5f) * 2.0f, 0);
|
||||
mLogo.setAlpha(alpha);
|
||||
} else {
|
||||
translationY += (mOffset - mStaticOffset) / 2;
|
||||
}
|
||||
mLogo.setTranslationX(translationX);
|
||||
mLogo.setTranslationY(translationY);
|
||||
}
|
||||
|
||||
private void updateCircleRect() {
|
||||
updateCircleRect(mCircleRect, mOffset, false);
|
||||
}
|
||||
|
||||
private void updateCircleRect(Rect rect, float offset, boolean useStaticSize) {
|
||||
int left, top;
|
||||
float circleSize = useStaticSize ? mCircleMinSize : mCircleSize;
|
||||
if (mHorizontal) {
|
||||
left = (int) (getWidth() - circleSize / 2 - mBaseMargin - offset);
|
||||
top = (int) ((getHeight() - circleSize) / 2);
|
||||
} else {
|
||||
left = (int) (getWidth() - circleSize) / 2;
|
||||
top = (int) (getHeight() - circleSize / 2 - mBaseMargin - offset);
|
||||
}
|
||||
rect.set(left, top, (int) (left + circleSize), (int) (top + circleSize));
|
||||
}
|
||||
|
||||
public void setHorizontal(boolean horizontal) {
|
||||
mHorizontal = horizontal;
|
||||
updateCircleRect(mStaticRect, mStaticOffset, true);
|
||||
updateLayout();
|
||||
}
|
||||
|
||||
public void setDragDistance(float distance) {
|
||||
if (!mAnimatingOut && (!mCircleHidden || mDraggedFarEnough)) {
|
||||
float circleSize = mCircleMinSize + rubberband(distance);
|
||||
setCircleSize(circleSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private float rubberband(float diff) {
|
||||
return (float) Math.pow(Math.abs(diff), 0.6f);
|
||||
}
|
||||
|
||||
public void startAbortAnimation(Runnable endRunnable) {
|
||||
if (mAnimatingOut) {
|
||||
if (endRunnable != null) {
|
||||
endRunnable.run();
|
||||
}
|
||||
return;
|
||||
}
|
||||
setCircleSize(0, true, null, 0, null);
|
||||
setOffset(0, true, 0, null, endRunnable);
|
||||
mCircleHidden = true;
|
||||
}
|
||||
|
||||
public void startEnterAnimation() {
|
||||
if (mAnimatingOut) {
|
||||
return;
|
||||
}
|
||||
applyCircleSize(0);
|
||||
setOffset(0);
|
||||
setCircleSize(mCircleMinSize, true, null, 50, null);
|
||||
setOffset(mStaticOffset, true, 50, null, null);
|
||||
mCircleHidden = false;
|
||||
}
|
||||
|
||||
|
||||
public void startExitAnimation(final Runnable endRunnable) {
|
||||
if (!mHorizontal) {
|
||||
float offset = getHeight() / 2.0f;
|
||||
setOffset(offset - mBaseMargin, true, 50, mFastOutSlowInInterpolator, null);
|
||||
float xMax = getWidth() / 2;
|
||||
float yMax = getHeight() / 2;
|
||||
float maxRadius = (float) Math.ceil(Math.hypot(xMax, yMax) * 2);
|
||||
setCircleSize(maxRadius, true, null, 50, mFastOutSlowInInterpolator);
|
||||
performExitFadeOutAnimation(50, 300, endRunnable);
|
||||
} else {
|
||||
|
||||
// when in landscape, we don't wan't the animation as it interferes with the general
|
||||
// rotation animation to the homescreen.
|
||||
endRunnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
private void performExitFadeOutAnimation(int startDelay, int duration,
|
||||
final Runnable endRunnable) {
|
||||
mFadeOutAnimator = ValueAnimator.ofFloat(mBackgroundPaint.getAlpha() / 255.0f, 0.0f);
|
||||
|
||||
// Linear since we are animating multiple values
|
||||
mFadeOutAnimator.setInterpolator(new LinearInterpolator());
|
||||
mFadeOutAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
float animatedFraction = animation.getAnimatedFraction();
|
||||
float logoValue = animatedFraction > 0.5f ? 1.0f : animatedFraction / 0.5f;
|
||||
logoValue = PhoneStatusBar.ALPHA_OUT.getInterpolation(1.0f - logoValue);
|
||||
float backgroundValue = animatedFraction < 0.2f ? 0.0f :
|
||||
PhoneStatusBar.ALPHA_OUT.getInterpolation((animatedFraction - 0.2f) / 0.8f);
|
||||
backgroundValue = 1.0f - backgroundValue;
|
||||
mBackgroundPaint.setAlpha((int) (backgroundValue * 255));
|
||||
mOutlineAlpha = backgroundValue;
|
||||
mLogo.setAlpha(logoValue);
|
||||
invalidateOutline();
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
mFadeOutAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (endRunnable != null) {
|
||||
endRunnable.run();
|
||||
}
|
||||
mLogo.setAlpha(1.0f);
|
||||
mBackgroundPaint.setAlpha(255);
|
||||
mOutlineAlpha = 1.0f;
|
||||
mFadeOutAnimator = null;
|
||||
}
|
||||
});
|
||||
mFadeOutAnimator.setStartDelay(startDelay);
|
||||
mFadeOutAnimator.setDuration(duration);
|
||||
mFadeOutAnimator.start();
|
||||
}
|
||||
|
||||
public void setDraggedFarEnough(boolean farEnough) {
|
||||
if (farEnough != mDraggedFarEnough) {
|
||||
if (farEnough) {
|
||||
if (mCircleHidden) {
|
||||
startEnterAnimation();
|
||||
}
|
||||
if (mOffsetAnimator == null) {
|
||||
addRipple();
|
||||
} else {
|
||||
postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
addRipple();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
} else {
|
||||
startAbortAnimation(null);
|
||||
}
|
||||
mDraggedFarEnough = farEnough;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void addRipple() {
|
||||
if (mRipples.size() > 1) {
|
||||
// we only want 2 ripples at the time
|
||||
return;
|
||||
}
|
||||
float xInterpolation, yInterpolation;
|
||||
if (mHorizontal) {
|
||||
xInterpolation = 0.75f;
|
||||
yInterpolation = 0.5f;
|
||||
} else {
|
||||
xInterpolation = 0.5f;
|
||||
yInterpolation = 0.75f;
|
||||
}
|
||||
float circleCenterX = mStaticRect.left * (1.0f - xInterpolation)
|
||||
+ mStaticRect.right * xInterpolation;
|
||||
float circleCenterY = mStaticRect.top * (1.0f - yInterpolation)
|
||||
+ mStaticRect.bottom * yInterpolation;
|
||||
float radius = Math.max(mCircleSize, mCircleMinSize * 1.25f) * 0.75f;
|
||||
Ripple ripple = new Ripple(circleCenterX, circleCenterY, radius);
|
||||
ripple.start();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
mDraggedFarEnough = false;
|
||||
mAnimatingOut = false;
|
||||
mCircleHidden = true;
|
||||
mClipToOutline = false;
|
||||
if (mFadeOutAnimator != null) {
|
||||
mFadeOutAnimator.cancel();
|
||||
}
|
||||
mBackgroundPaint.setAlpha(255);
|
||||
mOutlineAlpha = 1.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an animation is currently running
|
||||
*
|
||||
* @param enterAnimation Is the animating queried the enter animation.
|
||||
*/
|
||||
public boolean isAnimationRunning(boolean enterAnimation) {
|
||||
return mOffsetAnimator != null && (enterAnimation == mOffsetAnimatingIn);
|
||||
}
|
||||
|
||||
public void performOnAnimationFinished(final Runnable runnable) {
|
||||
if (mOffsetAnimator != null) {
|
||||
mOffsetAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (runnable != null) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (runnable != null) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setAnimatingOut(boolean animatingOut) {
|
||||
mAnimatingOut = animatingOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the circle is currently launching to the search activity or aborting the
|
||||
* interaction
|
||||
*/
|
||||
public boolean isAnimatingOut() {
|
||||
return mAnimatingOut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOverlappingRendering() {
|
||||
// not really true but it's ok during an animation, as it's never permanent
|
||||
return false;
|
||||
}
|
||||
|
||||
private class Ripple {
|
||||
float x;
|
||||
float y;
|
||||
float radius;
|
||||
float endRadius;
|
||||
float alpha;
|
||||
|
||||
Ripple(float x, float y, float endRadius) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.endRadius = endRadius;
|
||||
}
|
||||
|
||||
void start() {
|
||||
ValueAnimator animator = ValueAnimator.ofFloat(0.0f, 1.0f);
|
||||
|
||||
// Linear since we are animating multiple values
|
||||
animator.setInterpolator(new LinearInterpolator());
|
||||
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
alpha = 1.0f - animation.getAnimatedFraction();
|
||||
alpha = mDisappearInterpolator.getInterpolation(alpha);
|
||||
radius = mAppearInterpolator.getInterpolation(animation.getAnimatedFraction());
|
||||
radius *= endRadius;
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mRipples.remove(Ripple.this);
|
||||
updateClipping();
|
||||
}
|
||||
|
||||
public void onAnimationStart(Animator animation) {
|
||||
mRipples.add(Ripple.this);
|
||||
updateClipping();
|
||||
}
|
||||
});
|
||||
animator.setDuration(400);
|
||||
animator.start();
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas) {
|
||||
mRipplePaint.setAlpha((int) (alpha * 255));
|
||||
canvas.drawCircle(x, y, radius, mRipplePaint);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -16,10 +16,6 @@
|
||||
|
||||
package com.android.systemui;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.app.ActivityOptions;
|
||||
import android.app.SearchManager;
|
||||
import android.content.ActivityNotFoundException;
|
||||
@ -38,8 +34,6 @@ import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
|
||||
@ -62,26 +56,19 @@ public class SearchPanelView extends FrameLayout implements StatusBarPanel {
|
||||
private final Context mContext;
|
||||
private BaseStatusBar mBar;
|
||||
|
||||
private View mCard;
|
||||
private SearchPanelCircleView mCircle;
|
||||
private ImageView mLogo;
|
||||
private View mScrim;
|
||||
|
||||
private int mPeekHeight;
|
||||
private int mThreshold;
|
||||
private boolean mHorizontal;
|
||||
private final Interpolator mLinearOutSlowInInterpolator;
|
||||
private final Interpolator mFastOutLinearInInterpolator;
|
||||
|
||||
private boolean mAnimatingIn;
|
||||
private boolean mAnimatingOut;
|
||||
private boolean mLaunching;
|
||||
private boolean mDragging;
|
||||
private boolean mDraggedFarEnough;
|
||||
private float mStartTouch;
|
||||
private float mStartDrag;
|
||||
|
||||
private ObjectAnimator mEnterAnimator;
|
||||
|
||||
private boolean mStartExitAfterAnimatingIn;
|
||||
private boolean mLaunchPending;
|
||||
|
||||
public SearchPanelView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
@ -90,12 +77,7 @@ public class SearchPanelView extends FrameLayout implements StatusBarPanel {
|
||||
public SearchPanelView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mContext = context;
|
||||
mPeekHeight = context.getResources().getDimensionPixelSize(R.dimen.search_card_peek_height);
|
||||
mThreshold = context.getResources().getDimensionPixelSize(R.dimen.search_panel_threshold);
|
||||
mLinearOutSlowInInterpolator =
|
||||
AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
|
||||
mFastOutLinearInInterpolator =
|
||||
AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_linear_in);
|
||||
}
|
||||
|
||||
private void startAssistActivity() {
|
||||
@ -128,7 +110,7 @@ public class SearchPanelView extends FrameLayout implements StatusBarPanel {
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
mCard = findViewById(R.id.search_panel_card);
|
||||
mCircle = (SearchPanelCircleView) findViewById(R.id.search_panel_circle);
|
||||
mLogo = (ImageView) findViewById(R.id.search_logo);
|
||||
mScrim = findViewById(R.id.search_panel_scrim);
|
||||
}
|
||||
@ -170,16 +152,9 @@ public class SearchPanelView extends FrameLayout implements StatusBarPanel {
|
||||
v.setImageDrawable(null);
|
||||
}
|
||||
|
||||
private boolean pointInside(int x, int y, View v) {
|
||||
final int l = v.getLeft();
|
||||
final int r = v.getRight();
|
||||
final int t = v.getTop();
|
||||
final int b = v.getBottom();
|
||||
return x >= l && x < r && y >= t && y < b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInContentArea(int x, int y) {
|
||||
return pointInside(x, y, mCard);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void vibrate() {
|
||||
@ -199,16 +174,10 @@ public class SearchPanelView extends FrameLayout implements StatusBarPanel {
|
||||
if (getVisibility() != View.VISIBLE) {
|
||||
setVisibility(View.VISIBLE);
|
||||
vibrate();
|
||||
mCard.setAlpha(1f);
|
||||
if (animate) {
|
||||
startEnterAnimation();
|
||||
} else {
|
||||
mScrim.setAlpha(1f);
|
||||
if (mHorizontal) {
|
||||
mCard.setX(getWidth() - mPeekHeight);
|
||||
} else {
|
||||
mCard.setY(getHeight() - mPeekHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
setFocusable(true);
|
||||
@ -224,30 +193,7 @@ public class SearchPanelView extends FrameLayout implements StatusBarPanel {
|
||||
}
|
||||
|
||||
private void startEnterAnimation() {
|
||||
if (mHorizontal) {
|
||||
mCard.setX(getWidth());
|
||||
} else {
|
||||
mCard.setY(getHeight());
|
||||
}
|
||||
mAnimatingIn = true;
|
||||
mCard.animate().cancel();
|
||||
mEnterAnimator = ObjectAnimator.ofFloat(mCard, mHorizontal ? View.X : View.Y,
|
||||
mHorizontal ? mCard.getX() : mCard.getY(),
|
||||
mHorizontal ? getWidth() - mPeekHeight : getHeight() - mPeekHeight);
|
||||
mEnterAnimator.setDuration(300);
|
||||
mEnterAnimator.setStartDelay(50);
|
||||
mEnterAnimator.setInterpolator(mLinearOutSlowInInterpolator);
|
||||
mEnterAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mEnterAnimator = null;
|
||||
mAnimatingIn = false;
|
||||
if (mStartExitAfterAnimatingIn) {
|
||||
startExitAnimation();
|
||||
}
|
||||
}
|
||||
});
|
||||
mEnterAnimator.start();
|
||||
mCircle.startEnterAnimation();
|
||||
mScrim.setAlpha(0f);
|
||||
mScrim.animate()
|
||||
.alpha(1f)
|
||||
@ -259,26 +205,17 @@ public class SearchPanelView extends FrameLayout implements StatusBarPanel {
|
||||
}
|
||||
|
||||
private void startAbortAnimation() {
|
||||
mCard.animate().cancel();
|
||||
mAnimatingOut = true;
|
||||
if (mHorizontal) {
|
||||
mCard.animate().x(getWidth());
|
||||
} else {
|
||||
mCard.animate().y(getHeight());
|
||||
}
|
||||
mCard.animate()
|
||||
.setDuration(150)
|
||||
.setInterpolator(mFastOutLinearInInterpolator)
|
||||
.withEndAction(new Runnable() {
|
||||
mCircle.startAbortAnimation(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mAnimatingOut = false;
|
||||
mCircle.setAnimatingOut(false);
|
||||
setVisibility(View.INVISIBLE);
|
||||
}
|
||||
});
|
||||
mCircle.setAnimatingOut(true);
|
||||
mScrim.animate()
|
||||
.alpha(0f)
|
||||
.setDuration(150)
|
||||
.setDuration(300)
|
||||
.setStartDelay(0)
|
||||
.setInterpolator(PhoneStatusBar.ALPHA_OUT);
|
||||
}
|
||||
@ -314,7 +251,7 @@ public class SearchPanelView extends FrameLayout implements StatusBarPanel {
|
||||
* when the animation is done.
|
||||
*/
|
||||
public boolean isShowing() {
|
||||
return getVisibility() == View.VISIBLE && !mAnimatingOut;
|
||||
return getVisibility() == View.VISIBLE && !mCircle.isAnimatingOut();
|
||||
}
|
||||
|
||||
public void setBar(BaseStatusBar bar) {
|
||||
@ -326,60 +263,46 @@ public class SearchPanelView extends FrameLayout implements StatusBarPanel {
|
||||
.getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null;
|
||||
}
|
||||
|
||||
private float rubberband(float diff) {
|
||||
return Math.signum(diff) * (float) Math.pow(Math.abs(diff), 0.8f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (mLaunching || mLaunchPending) {
|
||||
return false;
|
||||
}
|
||||
int action = event.getActionMasked();
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mStartTouch = mHorizontal ? event.getX() : event.getY();
|
||||
mDragging = false;
|
||||
mDraggedFarEnough = false;
|
||||
mStartExitAfterAnimatingIn = false;
|
||||
mCircle.reset();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
float currentTouch = mHorizontal ? event.getX() : event.getY();
|
||||
if (getVisibility() == View.VISIBLE && !mDragging &&
|
||||
(!mAnimatingIn || Math.abs(mStartTouch - currentTouch) > mThreshold)) {
|
||||
(!mCircle.isAnimationRunning(true /* enterAnimation */)
|
||||
|| Math.abs(mStartTouch - currentTouch) > mThreshold)) {
|
||||
mStartDrag = currentTouch;
|
||||
mDragging = true;
|
||||
}
|
||||
if (!mDraggedFarEnough && Math.abs(mStartTouch - currentTouch) > mThreshold) {
|
||||
mDraggedFarEnough = true;
|
||||
}
|
||||
if (mDragging) {
|
||||
if (!mAnimatingIn && !mAnimatingOut) {
|
||||
if (Math.abs(currentTouch - mStartDrag) > mThreshold) {
|
||||
startExitAnimation();
|
||||
} else {
|
||||
if (mHorizontal) {
|
||||
mCard.setX(getWidth() - mPeekHeight + rubberband(
|
||||
currentTouch - mStartDrag));
|
||||
} else {
|
||||
mCard.setY(getHeight() - mPeekHeight + rubberband(
|
||||
currentTouch - mStartDrag));
|
||||
}
|
||||
}
|
||||
} else if (mAnimatingIn ) {
|
||||
float diff = rubberband(currentTouch - mStartDrag);
|
||||
PropertyValuesHolder[] values = mEnterAnimator.getValues();
|
||||
values[0].setFloatValues(
|
||||
mHorizontal ? getWidth() + diff : getHeight() + diff,
|
||||
mHorizontal
|
||||
? getWidth() - mPeekHeight + diff
|
||||
: getHeight() - mPeekHeight + diff);
|
||||
mEnterAnimator.setCurrentPlayTime(mEnterAnimator.getCurrentPlayTime());
|
||||
}
|
||||
float offset = Math.max(mStartDrag - currentTouch, 0.0f);
|
||||
mCircle.setDragDistance(offset);
|
||||
mDraggedFarEnough = Math.abs(mStartTouch - currentTouch) > mThreshold;
|
||||
mCircle.setDraggedFarEnough(mDraggedFarEnough);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if (mDraggedFarEnough) {
|
||||
if (mAnimatingIn) {
|
||||
mStartExitAfterAnimatingIn = true;
|
||||
if (mCircle.isAnimationRunning(true /* enterAnimation */)) {
|
||||
mLaunchPending = true;
|
||||
mCircle.setAnimatingOut(true);
|
||||
mCircle.performOnAnimationFinished(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
startExitAnimation();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
startExitAnimation();
|
||||
}
|
||||
@ -392,35 +315,31 @@ public class SearchPanelView extends FrameLayout implements StatusBarPanel {
|
||||
}
|
||||
|
||||
private void startExitAnimation() {
|
||||
if (mAnimatingOut || getVisibility() != View.VISIBLE) {
|
||||
mLaunchPending = false;
|
||||
if (mLaunching || getVisibility() != View.VISIBLE) {
|
||||
return;
|
||||
}
|
||||
if (mEnterAnimator != null) {
|
||||
mEnterAnimator.cancel();
|
||||
}
|
||||
mAnimatingOut = true;
|
||||
mLaunching = true;
|
||||
startAssistActivity();
|
||||
vibrate();
|
||||
mCard.animate()
|
||||
.alpha(0f)
|
||||
.withLayer()
|
||||
.setDuration(250)
|
||||
.setInterpolator(PhoneStatusBar.ALPHA_OUT)
|
||||
.withEndAction(new Runnable() {
|
||||
mCircle.setAnimatingOut(true);
|
||||
mCircle.startExitAnimation(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mAnimatingOut = false;
|
||||
mLaunching = false;
|
||||
mCircle.setAnimatingOut(false);
|
||||
setVisibility(View.INVISIBLE);
|
||||
}
|
||||
});
|
||||
mScrim.animate()
|
||||
.alpha(0f)
|
||||
.setDuration(250)
|
||||
.setDuration(300)
|
||||
.setStartDelay(0)
|
||||
.setInterpolator(PhoneStatusBar.ALPHA_OUT);
|
||||
}
|
||||
|
||||
public void setHorizontal(boolean horizontal) {
|
||||
mHorizontal = horizontal;
|
||||
mCircle.setHorizontal(horizontal);
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ import com.android.systemui.SystemUI;
|
||||
import com.android.systemui.statusbar.NotificationData.Entry;
|
||||
import com.android.systemui.statusbar.phone.KeyguardTouchDelegate;
|
||||
import com.android.systemui.statusbar.phone.PhoneStatusBar;
|
||||
import com.android.systemui.statusbar.phone.NavigationBarView;
|
||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
|
||||
import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
|
||||
import com.android.systemui.statusbar.policy.PreviewInflater;
|
||||
@ -165,6 +166,9 @@ public abstract class BaseStatusBar extends SystemUI implements
|
||||
|
||||
protected int mLayoutDirection = -1; // invalid
|
||||
protected AccessibilityManager mAccessibilityManager;
|
||||
|
||||
// on-screen navigation buttons
|
||||
protected NavigationBarView mNavigationBarView = null;
|
||||
private Locale mLocale;
|
||||
private float mFontScale;
|
||||
|
||||
@ -1006,6 +1010,8 @@ public abstract class BaseStatusBar extends SystemUI implements
|
||||
mSearchPanelView.setOnTouchListener(
|
||||
new TouchOutsideListener(MSG_CLOSE_SEARCH_PANEL, mSearchPanelView));
|
||||
mSearchPanelView.setVisibility(View.GONE);
|
||||
boolean vertical = mNavigationBarView != null && mNavigationBarView.isVertical();
|
||||
mSearchPanelView.setHorizontal(vertical);
|
||||
|
||||
WindowManager.LayoutParams lp = getSearchLayoutParams(mSearchPanelView.getLayoutParams());
|
||||
|
||||
|
@ -88,6 +88,7 @@ public class NavigationBarView extends LinearLayout {
|
||||
|
||||
private OnVerticalChangedListener mOnVerticalChangedListener;
|
||||
private boolean mIsLayoutRtl;
|
||||
private boolean mDelegateIntercepted;
|
||||
|
||||
private class NavTransitionListener implements TransitionListener {
|
||||
private boolean mBackTransitioning;
|
||||
@ -198,27 +199,45 @@ public class NavigationBarView extends LinearLayout {
|
||||
|
||||
public void setOnVerticalChangedListener(OnVerticalChangedListener onVerticalChangedListener) {
|
||||
mOnVerticalChangedListener = onVerticalChangedListener;
|
||||
notifyVerticalChangedListener(mVertical);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (mTaskSwitchHelper.onTouchEvent(event)) {
|
||||
initDownStates(event);
|
||||
if (!mDelegateIntercepted && mTaskSwitchHelper.onTouchEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
if (mDeadZone != null && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
|
||||
mDeadZone.poke(event);
|
||||
}
|
||||
if (mDelegateHelper != null) {
|
||||
if (mDelegateHelper != null && mDelegateIntercepted) {
|
||||
boolean ret = mDelegateHelper.onInterceptTouchEvent(event);
|
||||
if (ret) return true;
|
||||
}
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
private void initDownStates(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
mDelegateIntercepted = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
return mTaskSwitchHelper.onInterceptTouchEvent(event) ||
|
||||
mDelegateHelper.onInterceptTouchEvent(event);
|
||||
initDownStates(event);
|
||||
boolean intercept = mTaskSwitchHelper.onInterceptTouchEvent(event);
|
||||
if (!intercept) {
|
||||
mDelegateIntercepted = mDelegateHelper.onInterceptTouchEvent(event);
|
||||
intercept = mDelegateIntercepted;
|
||||
} else {
|
||||
MotionEvent cancelEvent = MotionEvent.obtain(event);
|
||||
cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
|
||||
mDelegateHelper.onInterceptTouchEvent(cancelEvent);
|
||||
cancelEvent.recycle();
|
||||
}
|
||||
return intercept;
|
||||
}
|
||||
|
||||
private H mHandler = new H();
|
||||
@ -426,12 +445,16 @@ public class NavigationBarView extends LinearLayout {
|
||||
if (mDelegateHelper != null) {
|
||||
mDelegateHelper.setSwapXY(mVertical);
|
||||
}
|
||||
boolean isRTL = (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
|
||||
mTaskSwitchHelper.setBarState(mVertical, isRTL);
|
||||
updateTaskSwitchHelper();
|
||||
|
||||
setNavigationIconHints(mNavigationIconHints, true);
|
||||
}
|
||||
|
||||
private void updateTaskSwitchHelper() {
|
||||
boolean isRtl = (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
|
||||
mTaskSwitchHelper.setBarState(mVertical, isRtl);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
super.onLayout(changed, l, t, r, b);
|
||||
@ -448,19 +471,24 @@ public class NavigationBarView extends LinearLayout {
|
||||
mVertical = newVertical;
|
||||
//Log.v(TAG, String.format("onSizeChanged: h=%d, w=%d, vert=%s", h, w, mVertical?"y":"n"));
|
||||
reorient();
|
||||
if (mOnVerticalChangedListener != null) {
|
||||
mOnVerticalChangedListener.onVerticalChanged(newVertical);
|
||||
}
|
||||
notifyVerticalChangedListener(newVertical);
|
||||
}
|
||||
|
||||
postCheckForInvalidLayout("sizeChanged");
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
}
|
||||
|
||||
private void notifyVerticalChangedListener(boolean newVertical) {
|
||||
if (mOnVerticalChangedListener != null) {
|
||||
mOnVerticalChangedListener.onVerticalChanged(newVertical);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
updateRTLOrder();
|
||||
updateTaskSwitchHelper();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,7 +55,7 @@ public class NavigationBarViewTaskSwitchHelper extends GestureDetector.SimpleOnG
|
||||
// task switcher detector
|
||||
mTaskSwitcherDetector.onTouchEvent(event);
|
||||
int action = event.getAction();
|
||||
boolean interceptTouches = false;
|
||||
boolean intercepted = false;
|
||||
switch (action & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
mTouchDownX = (int) event.getX();
|
||||
@ -71,7 +71,6 @@ public class NavigationBarViewTaskSwitchHelper extends GestureDetector.SimpleOnG
|
||||
? xDiff > mScrollTouchSlop && xDiff > yDiff
|
||||
: yDiff > mScrollTouchSlop && yDiff > xDiff;
|
||||
if (exceededTouchSlop) {
|
||||
interceptTouches = true;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@ -80,7 +79,7 @@ public class NavigationBarViewTaskSwitchHelper extends GestureDetector.SimpleOnG
|
||||
case MotionEvent.ACTION_UP:
|
||||
break;
|
||||
}
|
||||
return interceptTouches;
|
||||
return intercepted;
|
||||
}
|
||||
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
|
@ -316,8 +316,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
|
||||
int[] mPositionTmp = new int[2];
|
||||
boolean mExpandedVisible;
|
||||
|
||||
// on-screen navigation buttons
|
||||
private NavigationBarView mNavigationBarView = null;
|
||||
private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
|
||||
|
||||
// the tracker view
|
||||
|
Reference in New Issue
Block a user