Merge "Add swipe-to-dismiss support to PhoneWindow." into klp-modular-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
bd79652a9a
@@ -2850,6 +2850,7 @@ package android.app {
|
||||
method public void onUserInteraction();
|
||||
method protected void onUserLeaveHint();
|
||||
method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
|
||||
method public void onWindowDismissed();
|
||||
method public void onWindowFocusChanged(boolean);
|
||||
method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
|
||||
method public void openContextMenu(android.view.View);
|
||||
@@ -3366,6 +3367,7 @@ package android.app {
|
||||
method public boolean onTouchEvent(android.view.MotionEvent);
|
||||
method public boolean onTrackballEvent(android.view.MotionEvent);
|
||||
method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
|
||||
method public void onWindowDismissed();
|
||||
method public void onWindowFocusChanged(boolean);
|
||||
method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
|
||||
method public void openContextMenu(android.view.View);
|
||||
@@ -22701,6 +22703,7 @@ package android.service.dreams {
|
||||
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
|
||||
method public boolean onSearchRequested();
|
||||
method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
|
||||
method public void onWindowDismissed();
|
||||
method public void onWindowFocusChanged(boolean);
|
||||
method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
|
||||
method public void setContentView(int);
|
||||
@@ -28648,6 +28651,7 @@ package android.view {
|
||||
field public static final int FEATURE_OPTIONS_PANEL = 0; // 0x0
|
||||
field public static final int FEATURE_PROGRESS = 2; // 0x2
|
||||
field public static final int FEATURE_RIGHT_ICON = 4; // 0x4
|
||||
field public static final int FEATURE_SWIPE_TO_DISMISS = 11; // 0xb
|
||||
field public static final int ID_ANDROID_CONTENT = 16908290; // 0x1020002
|
||||
field public static final int PROGRESS_END = 10000; // 0x2710
|
||||
field public static final int PROGRESS_INDETERMINATE_OFF = -4; // 0xfffffffc
|
||||
@@ -28679,6 +28683,7 @@ package android.view {
|
||||
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
|
||||
method public abstract boolean onSearchRequested();
|
||||
method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
|
||||
method public abstract void onWindowDismissed();
|
||||
method public abstract void onWindowFocusChanged(boolean);
|
||||
method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
|
||||
}
|
||||
|
||||
@@ -2402,6 +2402,13 @@ public class Activity extends ContextThemeWrapper
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the main window associated with the activity has been dismissed.
|
||||
*/
|
||||
public void onWindowDismissed() {
|
||||
finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to process key events. You can override this to intercept all
|
||||
|
||||
@@ -695,6 +695,10 @@ public class Dialog implements DialogInterface, Window.Callback,
|
||||
|
||||
public void onDetachedFromWindow() {
|
||||
}
|
||||
|
||||
public void onWindowDismissed() {
|
||||
dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to process key events. You can override this to intercept all
|
||||
|
||||
@@ -300,6 +300,10 @@ public class DreamService extends Service implements Window.Callback {
|
||||
public void onDetachedFromWindow() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowDismissed() {
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void onPanelClosed(int featureId, Menu menu) {
|
||||
|
||||
@@ -90,11 +90,16 @@ public abstract class Window {
|
||||
*/
|
||||
public static final int FEATURE_ACTION_MODE_OVERLAY = 10;
|
||||
|
||||
/**
|
||||
* Flag for requesting a decoration-free window that is dismissed by swiping from the left.
|
||||
*/
|
||||
public static final int FEATURE_SWIPE_TO_DISMISS = 11;
|
||||
|
||||
/**
|
||||
* Max value used as a feature ID
|
||||
* @hide
|
||||
*/
|
||||
public static final int FEATURE_MAX = FEATURE_ACTION_MODE_OVERLAY;
|
||||
public static final int FEATURE_MAX = FEATURE_SWIPE_TO_DISMISS;
|
||||
|
||||
/** Flag for setting the progress bar's visibility to VISIBLE */
|
||||
public static final int PROGRESS_VISIBILITY_ON = -1;
|
||||
@@ -385,6 +390,12 @@ public abstract class Window {
|
||||
* @param mode The mode that was just finished.
|
||||
*/
|
||||
public void onActionModeFinished(ActionMode mode);
|
||||
|
||||
/**
|
||||
* Called when a window is dismissed. This informs the callback that the
|
||||
* window is gone, and it should finish itself.
|
||||
*/
|
||||
public void onWindowDismissed();
|
||||
}
|
||||
|
||||
public Window(Context context) {
|
||||
|
||||
282
core/java/com/android/internal/widget/SwipeDismissLayout.java
Normal file
282
core/java/com/android/internal/widget/SwipeDismissLayout.java
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* 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.internal.widget;
|
||||
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
/**
|
||||
* Special layout that finishes its activity when swiped away.
|
||||
*/
|
||||
public class SwipeDismissLayout extends FrameLayout {
|
||||
private static final String TAG = "SwipeDismissLayout";
|
||||
|
||||
private static final float TRANSLATION_MIN_ALPHA = 0.5f;
|
||||
|
||||
public interface OnDismissedListener {
|
||||
void onDismissed(SwipeDismissLayout layout);
|
||||
}
|
||||
|
||||
public interface OnSwipeProgressChangedListener {
|
||||
/**
|
||||
* Called when the layout has been swiped and the position of the window should change.
|
||||
*
|
||||
* @param progress A number in [-1, 1] representing how far to the left
|
||||
* or right the window has been swiped. Negative values are swipes
|
||||
* left, and positives are right.
|
||||
* @param translate A number in [-w, w], where w is the width of the
|
||||
* layout. This is equivalent to progress * layout.getWidth().
|
||||
*/
|
||||
void onSwipeProgressChanged(SwipeDismissLayout layout, float progress, float translate);
|
||||
|
||||
void onSwipeCancelled(SwipeDismissLayout layout);
|
||||
}
|
||||
|
||||
// Cached ViewConfiguration and system-wide constant values
|
||||
private int mSlop;
|
||||
private int mMinFlingVelocity;
|
||||
private int mMaxFlingVelocity;
|
||||
private long mAnimationTime;
|
||||
private TimeInterpolator mCancelInterpolator;
|
||||
private TimeInterpolator mDismissInterpolator;
|
||||
|
||||
// Transient properties
|
||||
private int mActiveTouchId;
|
||||
private float mDownX;
|
||||
private float mDownY;
|
||||
private boolean mSwiping;
|
||||
private boolean mDismissed;
|
||||
private boolean mDiscardIntercept;
|
||||
private VelocityTracker mVelocityTracker;
|
||||
private float mTranslationX;
|
||||
|
||||
private OnDismissedListener mDismissedListener;
|
||||
private OnSwipeProgressChangedListener mProgressListener;
|
||||
|
||||
public SwipeDismissLayout(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public SwipeDismissLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public SwipeDismissLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
ViewConfiguration vc = ViewConfiguration.get(getContext());
|
||||
mSlop = vc.getScaledTouchSlop();
|
||||
mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 16;
|
||||
mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
|
||||
mAnimationTime = getContext().getResources().getInteger(
|
||||
android.R.integer.config_shortAnimTime);
|
||||
mCancelInterpolator = new DecelerateInterpolator(1.5f);
|
||||
mDismissInterpolator = new AccelerateInterpolator(1.5f);
|
||||
}
|
||||
|
||||
public void setOnDismissedListener(OnDismissedListener listener) {
|
||||
mDismissedListener = listener;
|
||||
}
|
||||
|
||||
public void setOnSwipeProgressChangedListener(OnSwipeProgressChangedListener listener) {
|
||||
mProgressListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
// offset because the view is translated during swipe
|
||||
ev.offsetLocation(mTranslationX, 0);
|
||||
|
||||
switch (ev.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
resetMembers();
|
||||
mDownX = ev.getRawX();
|
||||
mDownY = ev.getRawY();
|
||||
mActiveTouchId = ev.getPointerId(0);
|
||||
mVelocityTracker = VelocityTracker.obtain();
|
||||
mVelocityTracker.addMovement(ev);
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
resetMembers();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (mVelocityTracker == null || mDiscardIntercept) {
|
||||
break;
|
||||
}
|
||||
|
||||
int pointerIndex = ev.findPointerIndex(mActiveTouchId);
|
||||
float dx = ev.getRawX() - mDownX;
|
||||
float x = ev.getX(pointerIndex);
|
||||
float y = ev.getY(pointerIndex);
|
||||
if (dx != 0 && canScroll(this, false, dx, x, y)) {
|
||||
mDiscardIntercept = true;
|
||||
break;
|
||||
}
|
||||
updateSwiping(ev);
|
||||
break;
|
||||
}
|
||||
|
||||
return !mDiscardIntercept && mSwiping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
if (mVelocityTracker == null) {
|
||||
return super.onTouchEvent(ev);
|
||||
}
|
||||
switch (ev.getActionMasked()) {
|
||||
case MotionEvent.ACTION_UP:
|
||||
updateDismiss(ev);
|
||||
if (mDismissed) {
|
||||
dismiss();
|
||||
} else if (mSwiping) {
|
||||
cancel();
|
||||
}
|
||||
resetMembers();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
cancel();
|
||||
resetMembers();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mVelocityTracker.addMovement(ev);
|
||||
updateSwiping(ev);
|
||||
updateDismiss(ev);
|
||||
if (mSwiping) {
|
||||
setProgress(ev.getRawX() - mDownX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setProgress(float deltaX) {
|
||||
mTranslationX = deltaX;
|
||||
if (mProgressListener != null) {
|
||||
mProgressListener.onSwipeProgressChanged(this, deltaX / getWidth(), deltaX);
|
||||
}
|
||||
}
|
||||
|
||||
private void dismiss() {
|
||||
if (mDismissedListener != null) {
|
||||
mDismissedListener.onDismissed(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected void cancel() {
|
||||
if (mProgressListener != null) {
|
||||
mProgressListener.onSwipeCancelled(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets internal members when canceling.
|
||||
*/
|
||||
private void resetMembers() {
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker.recycle();
|
||||
}
|
||||
mVelocityTracker = null;
|
||||
mTranslationX = 0;
|
||||
mDownX = 0;
|
||||
mDownY = 0;
|
||||
mSwiping = false;
|
||||
mDismissed = false;
|
||||
mDiscardIntercept = false;
|
||||
}
|
||||
|
||||
private void updateSwiping(MotionEvent ev) {
|
||||
if (!mSwiping) {
|
||||
float deltaX = ev.getRawX() - mDownX;
|
||||
float deltaY = ev.getRawY() - mDownY;
|
||||
mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < mSlop * 2;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDismiss(MotionEvent ev) {
|
||||
if (!mDismissed) {
|
||||
mVelocityTracker.addMovement(ev);
|
||||
mVelocityTracker.computeCurrentVelocity(1000);
|
||||
|
||||
float deltaX = ev.getRawX() - mDownX;
|
||||
float velocityX = mVelocityTracker.getXVelocity();
|
||||
float absVelocityX = Math.abs(velocityX);
|
||||
float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
|
||||
|
||||
if (deltaX > getWidth() / 2) {
|
||||
mDismissed = true;
|
||||
} else if (absVelocityX >= mMinFlingVelocity
|
||||
&& absVelocityX <= mMaxFlingVelocity
|
||||
&& absVelocityY < absVelocityX / 2
|
||||
&& velocityX > 0
|
||||
&& deltaX > 0) {
|
||||
mDismissed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests scrollability within child views of v in the direction of dx.
|
||||
*
|
||||
* @param v View to test for horizontal scrollability
|
||||
* @param checkV Whether the view v passed should itself be checked for scrollability (true),
|
||||
* or just its children (false).
|
||||
* @param dx Delta scrolled in pixels. Only the sign of this is used.
|
||||
* @param x X coordinate of the active touch point
|
||||
* @param y Y coordinate of the active touch point
|
||||
* @return true if child views of v can be scrolled by delta of dx.
|
||||
*/
|
||||
protected boolean canScroll(View v, boolean checkV, float dx, float x, float y) {
|
||||
if (v instanceof ViewGroup) {
|
||||
final ViewGroup group = (ViewGroup) v;
|
||||
final int scrollX = v.getScrollX();
|
||||
final int scrollY = v.getScrollY();
|
||||
final int count = group.getChildCount();
|
||||
for (int i = count - 1; i >= 0; i--) {
|
||||
final View child = group.getChildAt(i);
|
||||
if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&
|
||||
y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&
|
||||
canScroll(child, true, dx, x + scrollX - child.getLeft(),
|
||||
y + scrollY - child.getTop())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return checkV && v.canScrollHorizontally((int) -dx);
|
||||
}
|
||||
}
|
||||
26
core/res/res/anim/swipe_window_enter.xml
Normal file
26
core/res/res/anim/swipe_window_enter.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
** Copyright 2007, 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@interpolator/decelerate_quad" >
|
||||
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
|
||||
android:fillEnabled="true" android:fillBefore="true"
|
||||
android:fillAfter="true"
|
||||
android:duration="@android:integer/config_activityDefaultDur" />
|
||||
</set>
|
||||
26
core/res/res/anim/swipe_window_exit.xml
Normal file
26
core/res/res/anim/swipe_window_exit.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
** Copyright 2007, 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@interpolator/decelerate_quad" >
|
||||
<translate android:fromXDelta="0%" android:toXDelta="100%"
|
||||
android:fillEnabled="true" android:fillBefore="true"
|
||||
android:fillAfter="true"
|
||||
android:duration="400" />
|
||||
</set>
|
||||
27
core/res/res/layout/screen_swipe_dismiss.xml
Normal file
27
core/res/res/layout/screen_swipe_dismiss.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<!--
|
||||
This is a layout for a window whose resident activity is finished when swiped away.
|
||||
-->
|
||||
|
||||
<com.android.internal.widget.SwipeDismissLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
@@ -447,6 +447,10 @@
|
||||
to {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION}. -->
|
||||
<attr name="windowTranslucentNavigation" format="boolean" />
|
||||
|
||||
<!-- Flag to indicate that a window can be swiped away to be dismissed.
|
||||
Corresponds to {@link android.view.Window.FEATURE_SWIPE_TO_DISMISS} -->
|
||||
<attr name="windowSwipeToDismiss" format="boolean" />
|
||||
|
||||
<!-- ============ -->
|
||||
<!-- Alert Dialog styles -->
|
||||
<!-- ============ -->
|
||||
@@ -1604,6 +1608,7 @@
|
||||
<attr name="windowCloseOnTouchOutside" />
|
||||
<attr name="windowTranslucentStatus" />
|
||||
<attr name="windowTranslucentNavigation" />
|
||||
<attr name="windowSwipeToDismiss" />
|
||||
<!-- The minimum width the window is allowed to be, along the major
|
||||
axis of the screen. That is, when in landscape. Can be either
|
||||
an absolute dimension or a fraction of the screen size in that
|
||||
|
||||
@@ -225,6 +225,14 @@ please see styles_device_defaults.xml.
|
||||
<item name="windowExitAnimation">@anim/fast_fade_out</item>
|
||||
</style>
|
||||
|
||||
<!-- Window animations for swipe-dismissable windows. {@hide} -->
|
||||
<style name="Animation.SwipeDismiss">
|
||||
<item name="taskOpenEnterAnimation">@anim/swipe_window_enter</item>
|
||||
<item name="taskOpenExitAnimation">@anim/swipe_window_exit</item>
|
||||
<item name="taskCloseEnterAnimation">@anim/swipe_window_enter</item>
|
||||
<item name="taskCloseExitAnimation">@anim/swipe_window_exit</item>
|
||||
</style>
|
||||
|
||||
<!-- Status Bar Styles -->
|
||||
<style name="TextAppearance.StatusBar">
|
||||
<item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
|
||||
|
||||
@@ -1374,6 +1374,7 @@
|
||||
<java-symbol type="layout" name="screen_progress" />
|
||||
<java-symbol type="layout" name="screen_simple" />
|
||||
<java-symbol type="layout" name="screen_simple_overlay_action_mode" />
|
||||
<java-symbol type="layout" name="screen_swipe_dismiss" />
|
||||
<java-symbol type="layout" name="screen_title" />
|
||||
<java-symbol type="layout" name="screen_title_icons" />
|
||||
<java-symbol type="string" name="system_ui_date_pattern" />
|
||||
|
||||
@@ -16,22 +16,42 @@
|
||||
<resources>
|
||||
<style name="Theme.Micro" parent="Theme.Holo">
|
||||
<item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
|
||||
<item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
|
||||
<item name="windowIsFloating">false</item>
|
||||
<item name="windowIsTranslucent">true</item>
|
||||
<item name="windowSwipeToDismiss">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Micro.NoActionBar" parent="Theme.Holo.NoActionBar">
|
||||
<item name="textViewStyle">@android:style/Widget.Micro.TextView</item>
|
||||
<item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
|
||||
<item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
|
||||
<item name="windowIsFloating">false</item>
|
||||
<item name="windowIsTranslucent">true</item>
|
||||
<item name="windowSwipeToDismiss">true</item>
|
||||
</style>
|
||||
<style name="Theme.Micro.Light" parent="Theme.Holo.Light">
|
||||
<item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
|
||||
<item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
|
||||
<item name="windowIsFloating">false</item>
|
||||
<item name="windowIsTranslucent">true</item>
|
||||
<item name="windowSwipeToDismiss">true</item>
|
||||
</style>
|
||||
<style name="Theme.Micro.Light.NoActionBar" parent="Theme.Holo.Light.NoActionBar">
|
||||
<item name="textViewStyle">@android:style/Widget.Micro.TextView</item>
|
||||
<item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
|
||||
<item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
|
||||
<item name="windowIsFloating">false</item>
|
||||
<item name="windowIsTranslucent">true</item>
|
||||
<item name="windowSwipeToDismiss">true</item>
|
||||
</style>
|
||||
<style name="Theme.Micro.Light.DarkActionBar" parent="Theme.Holo.Light.DarkActionBar">
|
||||
<item name="textViewStyle">@android:style/Widget.Micro.TextView</item>
|
||||
<item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
|
||||
<item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
|
||||
<item name="windowIsFloating">false</item>
|
||||
<item name="windowIsTranslucent">true</item>
|
||||
<item name="windowSwipeToDismiss">true</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.android.internal.widget.ActionBarContainer;
|
||||
import com.android.internal.widget.ActionBarContextView;
|
||||
import com.android.internal.widget.ActionBarOverlayLayout;
|
||||
import com.android.internal.widget.ActionBarView;
|
||||
import com.android.internal.widget.SwipeDismissLayout;
|
||||
|
||||
import android.app.KeyguardManager;
|
||||
import android.content.Context;
|
||||
@@ -267,6 +268,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
|
||||
// Remove the action bar feature if we have no title. No title dominates.
|
||||
removeFeature(FEATURE_ACTION_BAR);
|
||||
}
|
||||
|
||||
if ((features & (1 << FEATURE_ACTION_BAR)) != 0 && featureId == FEATURE_SWIPE_TO_DISMISS) {
|
||||
throw new AndroidRuntimeException(
|
||||
"You cannot combine swipe dismissal and the action bar.");
|
||||
}
|
||||
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0 && featureId == FEATURE_ACTION_BAR) {
|
||||
throw new AndroidRuntimeException(
|
||||
"You cannot combine swipe dismissal and the action bar.");
|
||||
}
|
||||
return super.requestFeature(featureId);
|
||||
}
|
||||
|
||||
@@ -2838,6 +2848,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
|
||||
requestFeature(FEATURE_ACTION_MODE_OVERLAY);
|
||||
}
|
||||
|
||||
if (a.getBoolean(com.android.internal.R.styleable.Window_windowSwipeToDismiss, false)) {
|
||||
requestFeature(FEATURE_SWIPE_TO_DISMISS);
|
||||
}
|
||||
|
||||
if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {
|
||||
setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
|
||||
}
|
||||
@@ -2964,7 +2978,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
|
||||
int layoutResource;
|
||||
int features = getLocalFeatures();
|
||||
// System.out.println("Features: 0x" + Integer.toHexString(features));
|
||||
if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
|
||||
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
|
||||
layoutResource = com.android.internal.R.layout.screen_swipe_dismiss;
|
||||
} else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
|
||||
if (mIsFloating) {
|
||||
TypedValue res = new TypedValue();
|
||||
getContext().getTheme().resolveAttribute(
|
||||
@@ -3034,6 +3050,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
|
||||
registerSwipeCallbacks();
|
||||
}
|
||||
|
||||
// Remaining setup -- of background and title -- that only applies
|
||||
// to top-level windows.
|
||||
if (getContainer() == null) {
|
||||
@@ -3390,6 +3410,53 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
|
||||
return (mRightIconView = (ImageView)findViewById(com.android.internal.R.id.right_icon));
|
||||
}
|
||||
|
||||
private void registerSwipeCallbacks() {
|
||||
SwipeDismissLayout swipeDismiss =
|
||||
(SwipeDismissLayout) findViewById(com.android.internal.R.id.content);
|
||||
swipeDismiss.setOnDismissedListener(new SwipeDismissLayout.OnDismissedListener() {
|
||||
@Override
|
||||
public void onDismissed(SwipeDismissLayout layout) {
|
||||
Callback cb = getCallback();
|
||||
if (cb != null) {
|
||||
try {
|
||||
cb.onWindowDismissed();
|
||||
} catch (AbstractMethodError e) {
|
||||
Log.e(TAG, "onWindowDismissed not implemented in " +
|
||||
cb.getClass().getSimpleName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
swipeDismiss.setOnSwipeProgressChangedListener(
|
||||
new SwipeDismissLayout.OnSwipeProgressChangedListener() {
|
||||
private boolean mIsTranslucent = false;
|
||||
|
||||
@Override
|
||||
public void onSwipeProgressChanged(
|
||||
SwipeDismissLayout layout, float progress, float translate) {
|
||||
WindowManager.LayoutParams newParams = getAttributes();
|
||||
newParams.x = (int) translate;
|
||||
setAttributes(newParams);
|
||||
|
||||
int flags = 0;
|
||||
if (newParams.x == 0) {
|
||||
flags = FLAG_FULLSCREEN;
|
||||
} else {
|
||||
flags = FLAG_LAYOUT_NO_LIMITS;
|
||||
}
|
||||
setFlags(flags, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwipeCancelled(SwipeDismissLayout layout) {
|
||||
WindowManager.LayoutParams newParams = getAttributes();
|
||||
newParams.x = 0;
|
||||
setAttributes(newParams);
|
||||
setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for calling the {@link Callback#onPanelClosed(int, Menu)}
|
||||
* callback. This method will grab whatever extra state is needed for the
|
||||
|
||||
Reference in New Issue
Block a user