summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Haldean Brown <haldean@google.com>2014-03-04 15:54:13 -0800
committerAndroid Git Automerger <android-git-automerger@android.com>2014-03-04 15:54:13 -0800
commit8055195f992f4cdbea6172c18afe2f3809de7a39 (patch)
treec1da01127cb72eacc5bee724aa08623b34999854
parentbd4c10f8d7069cfbd8bb9b1c6879f85074c471b9 (diff)
parent568628dc2cb92b3ec3a87cae9de3203fbdc5968c (diff)
downloadframeworks_base-8055195f992f4cdbea6172c18afe2f3809de7a39.zip
frameworks_base-8055195f992f4cdbea6172c18afe2f3809de7a39.tar.gz
frameworks_base-8055195f992f4cdbea6172c18afe2f3809de7a39.tar.bz2
am 568628dc: Manually merge commit \'2faf28cf\' into master
* commit '568628dc2cb92b3ec3a87cae9de3203fbdc5968c': Add swipe-to-dismiss support to PhoneWindow.
-rw-r--r--api/current.txt5
-rw-r--r--core/java/android/app/Activity.java7
-rw-r--r--core/java/android/app/Dialog.java4
-rw-r--r--core/java/android/service/dreams/DreamService.java4
-rw-r--r--core/java/android/view/Window.java12
-rw-r--r--core/java/com/android/internal/widget/SwipeDismissLayout.java282
-rw-r--r--core/res/res/anim/swipe_window_enter.xml26
-rw-r--r--core/res/res/anim/swipe_window_exit.xml26
-rw-r--r--core/res/res/layout/screen_swipe_dismiss.xml27
-rw-r--r--core/res/res/values/attrs.xml5
-rw-r--r--core/res/res/values/styles.xml8
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/res/res/values/themes_micro.xml20
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java69
14 files changed, 494 insertions, 2 deletions
diff --git a/api/current.txt b/api/current.txt
index 55cb13b..7051d6c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3120,6 +3120,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);
@@ -3641,6 +3642,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);
@@ -23741,6 +23743,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);
@@ -30139,6 +30142,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
@@ -30170,6 +30174,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);
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 3297fe0..af4a362 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2462,6 +2462,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
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 2559254..fb96d8d 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -707,6 +707,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
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 1abb1d7..7647c22 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -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) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 24b8248..0cd6325 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -98,6 +98,10 @@ 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;
+ /**
* Flag for requesting that window content changes should be represented
* with scenes and transitions.
*
@@ -105,7 +109,7 @@ public abstract class Window {
*
* @see #setContentView
*/
- public static final int FEATURE_CONTENT_TRANSITIONS = 11;
+ public static final int FEATURE_CONTENT_TRANSITIONS = 12;
/**
* Max value used as a feature ID
@@ -404,6 +408,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) {
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
new file mode 100644
index 0000000..cc8ce2c
--- /dev/null
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -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);
+ }
+}
diff --git a/core/res/res/anim/swipe_window_enter.xml b/core/res/res/anim/swipe_window_enter.xml
new file mode 100644
index 0000000..e1617e2
--- /dev/null
+++ b/core/res/res/anim/swipe_window_enter.xml
@@ -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>
diff --git a/core/res/res/anim/swipe_window_exit.xml b/core/res/res/anim/swipe_window_exit.xml
new file mode 100644
index 0000000..ed0c5d3
--- /dev/null
+++ b/core/res/res/anim/swipe_window_exit.xml
@@ -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>
diff --git a/core/res/res/layout/screen_swipe_dismiss.xml b/core/res/res/layout/screen_swipe_dismiss.xml
new file mode 100644
index 0000000..90e970f
--- /dev/null
+++ b/core/res/res/layout/screen_swipe_dismiss.xml
@@ -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"
+ />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 039bd07..a78ce02 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -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" />
+
<!-- Flag indicating whether this window requests that content changes be performed
as scene changes with transitions. Corresponds to
{@link android.view.Window#FEATURE_CONTENT_TRANSITIONS}. -->
@@ -1629,6 +1633,7 @@
<attr name="windowCloseOnTouchOutside" />
<attr name="windowTranslucentStatus" />
<attr name="windowTranslucentNavigation" />
+ <attr name="windowSwipeToDismiss" />
<attr name="windowContentTransitions" />
<attr name="windowContentTransitionManager" />
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 1a6eacd..e525ef7 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -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>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9f368c4..a4f9762 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1370,6 +1370,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" />
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index b174d22..42f64fe 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -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>
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 02a2680..977c2e7 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -47,6 +47,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;
@@ -295,6 +296,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);
}
@@ -2924,6 +2934,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()));
}
@@ -3053,7 +3067,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(
@@ -3123,6 +3139,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) {
@@ -3493,6 +3513,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