summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Miller <jaggies@google.com>2013-09-10 18:37:01 -0700
committerJim Miller <jaggies@google.com>2013-09-19 17:14:59 -0700
commitcaf24fc2c4bb9747eb80138bf3ce0be067851749 (patch)
treea81859dd75a9ca17e752c32f1ecf0b40a62df1bd
parentf429247867ac524cf63bc01499ac47a90ebcaca9 (diff)
downloadframeworks_base-caf24fc2c4bb9747eb80138bf3ce0be067851749.zip
frameworks_base-caf24fc2c4bb9747eb80138bf3ce0be067851749.tar.gz
frameworks_base-caf24fc2c4bb9747eb80138bf3ce0be067851749.tar.bz2
Add camera affordance to navigation bar on phones
This adds a camera button on phones that can be used to show and launch the camera. - Minor refactoring of touch event dispatch in PagedView. - Disables usability hints when keyguard loads. - Only add a touch handler for camera icon once during layout. - Update after review. - Updated with latest UX camera and camera background assets Change-Id: I09cd5cb0e501fd0f4659bea96d00c92b07f805c4
-rw-r--r--core/java/com/android/internal/policy/IKeyguardService.aidl3
-rw-r--r--packages/Keyguard/res/drawable-hdpi/kg_widget_bg_padded.9.pngbin3272 -> 591 bytes
-rw-r--r--packages/Keyguard/res/drawable-mdpi/kg_widget_bg_padded.9.pngbin3149 -> 535 bytes
-rw-r--r--packages/Keyguard/res/drawable-xhdpi/kg_widget_bg_padded.9.pngbin3474 -> 621 bytes
-rw-r--r--packages/Keyguard/res/drawable-xxhdpi/kg_widget_bg_padded.9.pngbin0 -> 1163 bytes
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java5
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardService.java5
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java7
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java14
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java16
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java33
-rw-r--r--packages/Keyguard/src/com/android/keyguard/PagedView.java220
-rw-r--r--packages/SystemUI/AndroidManifest.xml5
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.pngbin0 -> 1988 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.pngbin0 -> 1406 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.pngbin0 -> 2596 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.pngbin0 -> 2885 bytes
-rw-r--r--packages/SystemUI/res/layout/navigation_bar.xml35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java106
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java76
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java6
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java5
23 files changed, 454 insertions, 83 deletions
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index d1f7fa3..dd2e006 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -15,6 +15,8 @@
*/
package com.android.internal.policy;
+import android.view.MotionEvent;
+
import com.android.internal.policy.IKeyguardShowCallback;
import com.android.internal.policy.IKeyguardExitCallback;
@@ -39,4 +41,5 @@ interface IKeyguardService {
oneway void doKeyguardTimeout(in Bundle options);
oneway void setCurrentUser(int userId);
oneway void showAssistant();
+ oneway void dispatch(in MotionEvent event);
}
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_widget_bg_padded.9.png b/packages/Keyguard/res/drawable-hdpi/kg_widget_bg_padded.9.png
index dff1dfa..c697f44 100644
--- a/packages/Keyguard/res/drawable-hdpi/kg_widget_bg_padded.9.png
+++ b/packages/Keyguard/res/drawable-hdpi/kg_widget_bg_padded.9.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_widget_bg_padded.9.png b/packages/Keyguard/res/drawable-mdpi/kg_widget_bg_padded.9.png
index c313df1..562bc7e 100644
--- a/packages/Keyguard/res/drawable-mdpi/kg_widget_bg_padded.9.png
+++ b/packages/Keyguard/res/drawable-mdpi/kg_widget_bg_padded.9.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_widget_bg_padded.9.png b/packages/Keyguard/res/drawable-xhdpi/kg_widget_bg_padded.9.png
index a84bfa3..b3edfd7 100644
--- a/packages/Keyguard/res/drawable-xhdpi/kg_widget_bg_padded.9.png
+++ b/packages/Keyguard/res/drawable-xhdpi/kg_widget_bg_padded.9.png
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xxhdpi/kg_widget_bg_padded.9.png b/packages/Keyguard/res/drawable-xxhdpi/kg_widget_bg_padded.9.png
new file mode 100644
index 0000000..8d31fee
--- /dev/null
+++ b/packages/Keyguard/res/drawable-xxhdpi/kg_widget_bg_padded.9.png
Binary files differ
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index fbe3a9c..0787286 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -1650,4 +1650,9 @@ public class KeyguardHostView extends KeyguardViewBase {
mActivityLauncher.launchActivityWithAnimation(
intent, false, opts.toBundle(), null, null);
}
+
+ public void dispatch(MotionEvent event) {
+ mAppWidgetContainer.handleExternalCameraEvent(event);
+ }
+
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
index a70e5bd..77006c5 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
@@ -28,6 +28,7 @@ import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
import android.util.Log;
+import android.view.MotionEvent;
import com.android.internal.policy.IKeyguardService;
import com.android.internal.policy.IKeyguardExitCallback;
@@ -132,6 +133,10 @@ public class KeyguardService extends Service {
checkPermission();
mKeyguardViewMediator.showAssistant();
}
+ public void dispatch(MotionEvent event) {
+ checkPermission();
+ mKeyguardViewMediator.dispatch(event);
+ }
};
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
index 35bea26..4837458 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
@@ -38,6 +38,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.view.KeyEvent;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewManager;
@@ -425,4 +426,10 @@ public class KeyguardViewManager {
mKeyguardView.showAssistant();
}
}
+
+ public void dispatch(MotionEvent event) {
+ if (mKeyguardView != null) {
+ mKeyguardView.dispatch(event);
+ }
+ }
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
index e746f72..478096c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
@@ -49,6 +49,7 @@ import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.WindowManagerPolicy;
@@ -120,6 +121,7 @@ public class KeyguardViewMediator {
private static final int SET_HIDDEN = 12;
private static final int KEYGUARD_TIMEOUT = 13;
private static final int SHOW_ASSISTANT = 14;
+ private static final int DISPATCH_EVENT = 15;
/**
* The default amount of time we stay awake (used for all key input)
@@ -1066,6 +1068,9 @@ public class KeyguardViewMediator {
case SHOW_ASSISTANT:
handleShowAssistant();
break;
+ case DISPATCH_EVENT:
+ handleDispatchEvent((MotionEvent) msg.obj);
+ break;
}
}
};
@@ -1102,6 +1107,10 @@ public class KeyguardViewMediator {
sendUserPresentBroadcast();
}
+ protected void handleDispatchEvent(MotionEvent event) {
+ mKeyguardViewManager.dispatch(event);
+ }
+
private void sendUserPresentBroadcast() {
final UserHandle currentUser = new UserHandle(mLockPatternUtils.getCurrentUser());
mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, currentUser);
@@ -1327,4 +1336,9 @@ public class KeyguardViewMediator {
public static MultiUserAvatarCache getAvatarCache() {
return sMultiUserAvatarCache;
}
+
+ public void dispatch(MotionEvent event) {
+ Message msg = mHandler.obtainMessage(DISPATCH_EVENT, event);
+ mHandler.sendMessage(msg);
+ }
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
index e85f6df..0539e82 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
@@ -23,6 +23,7 @@ public class KeyguardViewStateManager implements
SlidingChallengeLayout.OnChallengeScrolledListener,
ChallengeLayout.OnBouncerStateChangedListener {
+ private static final int WARP_FADE_DURATION = 250;
private KeyguardWidgetPager mKeyguardWidgetPager;
private ChallengeLayout mChallengeLayout;
private KeyguardHostView mKeyguardHostView;
@@ -32,6 +33,7 @@ public class KeyguardViewStateManager implements
private KeyguardSecurityView mKeyguardSecurityContainer;
private static final int SCREEN_ON_HINT_DURATION = 1000;
private static final int SCREEN_ON_RING_HINT_DELAY = 300;
+ private static final boolean SHOW_INITIAL_PAGE_HINTS = false;
Handler mMainQueue = new Handler(Looper.myLooper());
int mLastScrollState = SlidingChallengeLayout.SCROLL_STATE_IDLE;
@@ -167,6 +169,16 @@ public class KeyguardViewStateManager implements
mCurrentPage = newPageIndex;
}
+ public void onPageBeginWarp() {
+ // fadeOutSecurity(WARP_FADE_DURATION);
+ // mKeyguardWidgetPager.showNonWarpViews(WARP_FADE_DURATION, false);
+ }
+
+ public void onPageEndWarp() {
+ // fadeInSecurity(WARP_FADE_DURATION);
+ // mKeyguardWidgetPager.showNonWarpViews(WARP_FADE_DURATION, true);
+ }
+
private int getChallengeTopRelativeToFrame(KeyguardWidgetFrame frame, int top) {
mTmpPoint[0] = 0;
mTmpPoint[1] = top;
@@ -296,7 +308,9 @@ public class KeyguardViewStateManager implements
mKeyguardSecurityContainer.showUsabilityHint();
}
} , SCREEN_ON_RING_HINT_DELAY);
- mKeyguardWidgetPager.showInitialPageHints();
+ if (SHOW_INITIAL_PAGE_HINTS) {
+ mKeyguardWidgetPager.showInitialPageHints();
+ }
if (mHideHintsRunnable != null) {
mMainQueue.postDelayed(mHideHintsRunnable, SCREEN_ON_HINT_DURATION);
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
index c566457..8d2f21b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
@@ -186,6 +186,16 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
}
@Override
+ public void onPageBeginWarp() {
+ mViewStateManager.onPageBeginWarp();
+ }
+
+ @Override
+ public void onPageEndWarp() {
+ mViewStateManager.onPageEndWarp();
+ }
+
+ @Override
public void sendAccessibilityEvent(int eventType) {
if (eventType != AccessibilityEvent.TYPE_VIEW_SCROLLED || isPageMoving()) {
super.sendAccessibilityEvent(eventType);
@@ -923,4 +933,27 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
return flags;
}
+
+ public void handleExternalCameraEvent(MotionEvent event) {
+ beginCameraEvent();
+ int cameraPage = getPageCount() - 1;
+ boolean endWarp = false;
+ if (isCameraPage(cameraPage)) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ userActivity();
+ startWarp(cameraPage);
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ endWarp = true;
+ break;
+ }
+ dispatchTouchEvent(event);
+ // This has to happen after the event has been handled by the real widget pager
+ if (endWarp) endWarp();
+ }
+ endCameraEvent();
+ }
+
}
diff --git a/packages/Keyguard/src/com/android/keyguard/PagedView.java b/packages/Keyguard/src/com/android/keyguard/PagedView.java
index 881d14d..cbf7946 100644
--- a/packages/Keyguard/src/com/android/keyguard/PagedView.java
+++ b/packages/Keyguard/src/com/android/keyguard/PagedView.java
@@ -62,6 +62,7 @@ import java.util.ArrayList;
public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeListener {
private static final String TAG = "WidgetPagedView";
private static final boolean DEBUG = false;
+ private static final boolean DEBUG_WARP = false;
protected static final int INVALID_PAGE = -1;
// the min drag distance for a fling to register, to prevent random page shifts
@@ -130,6 +131,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
protected final static int TOUCH_STATE_REORDERING = 4;
protected final static float ALPHA_QUANTIZE_LEVEL = 0.0001f;
+ protected final static float TOUCH_SLOP_SCALE = 1.0f;
protected int mTouchState = TOUCH_STATE_REST;
protected boolean mForceScreenScrolled = false;
@@ -250,6 +252,10 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
// Bouncer
private boolean mTopAlignPageWhenShrinkingForBouncer = false;
+ // Page warping
+ private int mPageSwapIndex = -1;
+ private boolean mIsCameraEvent;
+
public interface PageSwitchListener {
void onPageSwitching(View newPage, int newPageIndex);
void onPageSwitched(View newPage, int newPageIndex);
@@ -469,15 +475,26 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
protected void pageBeginMoving() {
+ if (DEBUG_WARP) Log.v(TAG, "pageBeginMoving(" + mIsPageMoving + ")");
if (!mIsPageMoving) {
mIsPageMoving = true;
+ if (mPageSwapIndex != -1) {
+ onPageBeginWarp();
+ swapPages(mPageSwapIndex, getPageCount() - 1);
+ }
onPageBeginMoving();
}
}
protected void pageEndMoving() {
+ if (DEBUG_WARP) Log.v(TAG, "pageEndMoving(" + mIsPageMoving + ")");
if (mIsPageMoving) {
mIsPageMoving = false;
+ if (mPageSwapIndex != -1) {
+ swapPages(mPageSwapIndex, getPageCount() - 1);
+ onPageEndWarp();
+ mPageSwapIndex = -1;
+ }
onPageEndMoving();
}
}
@@ -737,6 +754,11 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
setHorizontalScrollBarEnabled(true);
mFirstLayout = false;
}
+ // If a page was swapped when we rebuilt the layout, swap it again now.
+ if (mPageSwapIndex != -1) {
+ if (DEBUG_WARP) Log.v(TAG, "onLayout: swapping pages");
+ swapPages(mPageSwapIndex, getPageCount() - 1);
+ }
}
protected void screenScrolled(int screenCenter) {
@@ -1071,7 +1093,9 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
* whether the user has moved far enough from his original down touch.
*/
if (mActivePointerId != INVALID_POINTER) {
- determineScrollingStart(ev);
+ if (mIsCameraEvent || determineScrollingStart(ev)) {
+ startScrolling(ev);
+ }
break;
}
// if mActivePointerId is INVALID_POINTER, then we must have missed an ACTION_DOWN
@@ -1082,27 +1106,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
case MotionEvent.ACTION_DOWN: {
- final float x = ev.getX();
- final float y = ev.getY();
- // Remember location of down touch
- mDownMotionX = x;
- mDownMotionY = y;
- mDownScrollX = getScrollX();
- mLastMotionX = x;
- mLastMotionY = y;
- float[] p = mapPointFromViewToParent(this, x, y);
- mParentDownMotionX = p[0];
- mParentDownMotionY = p[1];
- mLastMotionXRemainder = 0;
- mTotalMotionX = 0;
- mActivePointerId = ev.getPointerId(0);
-
- // Determine if the down event is within the threshold to be an edge swipe
- int leftEdgeBoundary = getViewportOffsetX() + mEdgeSwipeRegionSize;
- int rightEdgeBoundary = getMeasuredWidth() - getViewportOffsetX() - mEdgeSwipeRegionSize;
- if ((mDownMotionX <= leftEdgeBoundary || mDownMotionX >= rightEdgeBoundary)) {
- mDownEventOnEdge = true;
- }
+ // Remember where the motion event started
+ saveDownState(ev);
/*
* If being flinged and user touches the screen, initiate drag;
@@ -1112,25 +1117,29 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
final int xDist = Math.abs(mScroller.getFinalX() - mScroller.getCurrX());
final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop);
if (finishedScrolling) {
- mTouchState = TOUCH_STATE_REST;
+ setTouchState(TOUCH_STATE_REST);
mScroller.abortAnimation();
} else {
- if (isTouchPointInViewportWithBuffer((int) mDownMotionX, (int) mDownMotionY)) {
- mTouchState = TOUCH_STATE_SCROLLING;
+ if (mIsCameraEvent || isTouchPointInViewportWithBuffer(
+ (int) mDownMotionX, (int) mDownMotionY)) {
+ setTouchState(TOUCH_STATE_SCROLLING);
} else {
- mTouchState = TOUCH_STATE_REST;
+ setTouchState(TOUCH_STATE_REST);
}
}
// check if this can be the beginning of a tap on the side of the pages
// to scroll the current page
if (!DISABLE_TOUCH_SIDE_PAGES) {
- if (mTouchState != TOUCH_STATE_PREV_PAGE && mTouchState != TOUCH_STATE_NEXT_PAGE) {
+ if (mTouchState != TOUCH_STATE_PREV_PAGE
+ && mTouchState != TOUCH_STATE_NEXT_PAGE) {
if (getChildCount() > 0) {
+ float x = ev.getX();
+ float y = ev.getY();
if (hitsPreviousPage(x, y)) {
- mTouchState = TOUCH_STATE_PREV_PAGE;
+ setTouchState(TOUCH_STATE_PREV_PAGE);
} else if (hitsNextPage(x, y)) {
- mTouchState = TOUCH_STATE_NEXT_PAGE;
+ setTouchState(TOUCH_STATE_NEXT_PAGE);
}
}
}
@@ -1160,48 +1169,85 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
return mTouchState != TOUCH_STATE_REST;
}
- protected void determineScrollingStart(MotionEvent ev) {
- determineScrollingStart(ev, 1.0f);
+ private void setTouchState(int touchState) {
+ if (mTouchState != touchState) {
+ onTouchStateChanged(touchState);
+ mTouchState = touchState;
+ }
+ }
+
+ void onTouchStateChanged(int newTouchState) {
+ if (DEBUG) {
+ Log.v(TAG, "onTouchStateChanged(old="+ mTouchState + ", new=" + newTouchState + ")");
+ }
+ }
+
+ /**
+ * Save the state when we get {@link MotionEvent#ACTION_DOWN}
+ * @param ev
+ */
+ private void saveDownState(MotionEvent ev) {
+ // Remember where the motion event started
+ mDownMotionX = mLastMotionX = ev.getX();
+ mDownMotionY = mLastMotionY = ev.getY();
+ mDownScrollX = getScrollX();
+ float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
+ mParentDownMotionX = p[0];
+ mParentDownMotionY = p[1];
+ mLastMotionXRemainder = 0;
+ mTotalMotionX = 0;
+ mActivePointerId = ev.getPointerId(0);
+
+ // Determine if the down event is within the threshold to be an edge swipe
+ int leftEdgeBoundary = getViewportOffsetX() + mEdgeSwipeRegionSize;
+ int rightEdgeBoundary = getMeasuredWidth() - getViewportOffsetX() - mEdgeSwipeRegionSize;
+ if ((mDownMotionX <= leftEdgeBoundary || mDownMotionX >= rightEdgeBoundary)) {
+ mDownEventOnEdge = true;
+ }
}
/*
* Determines if we should change the touch state to start scrolling after the
* user moves their touch point too far.
*/
- protected void determineScrollingStart(MotionEvent ev, float touchSlopScale) {
+ protected boolean determineScrollingStart(MotionEvent ev) {
// Disallow scrolling if we don't have a valid pointer index
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
- if (pointerIndex == -1) return;
+ if (pointerIndex == -1) return false;
// Disallow scrolling if we started the gesture from outside the viewport
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
- if (!isTouchPointInViewportWithBuffer((int) x, (int) y)) return;
+ if (!isTouchPointInViewportWithBuffer((int) x, (int) y)) return false;
// If we're only allowing edge swipes, we break out early if the down event wasn't
// at the edge.
- if (mOnlyAllowEdgeSwipes && !mDownEventOnEdge) return;
+ if (mOnlyAllowEdgeSwipes && !mDownEventOnEdge) return false;
final int xDiff = (int) Math.abs(x - mLastMotionX);
final int yDiff = (int) Math.abs(y - mLastMotionY);
- final int touchSlop = Math.round(touchSlopScale * mTouchSlop);
+ final int touchSlop = Math.round(TOUCH_SLOP_SCALE * mTouchSlop);
boolean xPaged = xDiff > mPagingTouchSlop;
boolean xMoved = xDiff > touchSlop;
boolean yMoved = yDiff > touchSlop;
- if (xMoved || xPaged || yMoved) {
- if (mUsePagingTouchSlop ? xPaged : xMoved) {
- // Scroll if the user moved far enough along the X axis
- mTouchState = TOUCH_STATE_SCROLLING;
- mTotalMotionX += Math.abs(mLastMotionX - x);
- mLastMotionX = x;
- mLastMotionXRemainder = 0;
- mTouchX = getViewportOffsetX() + getScrollX();
- mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
- pageBeginMoving();
- }
- }
+ return (xMoved || xPaged || yMoved) && (mUsePagingTouchSlop ? xPaged : xMoved);
+ }
+
+ private void startScrolling(MotionEvent ev) {
+ // Ignore if we don't have a valid pointer index
+ final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (pointerIndex == -1) return;
+
+ final float x = ev.getX(pointerIndex);
+ setTouchState(TOUCH_STATE_SCROLLING);
+ mTotalMotionX += Math.abs(mLastMotionX - x);
+ mLastMotionX = x;
+ mLastMotionXRemainder = 0;
+ mTouchX = getViewportOffsetX() + getScrollX();
+ mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
+ pageBeginMoving();
}
protected float getMaxScrollProgress() {
@@ -1322,22 +1368,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
// Remember where the motion event started
- mDownMotionX = mLastMotionX = ev.getX();
- mDownMotionY = mLastMotionY = ev.getY();
- mDownScrollX = getScrollX();
- float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
- mParentDownMotionX = p[0];
- mParentDownMotionY = p[1];
- mLastMotionXRemainder = 0;
- mTotalMotionX = 0;
- mActivePointerId = ev.getPointerId(0);
-
- // Determine if the down event is within the threshold to be an edge swipe
- int leftEdgeBoundary = getViewportOffsetX() + mEdgeSwipeRegionSize;
- int rightEdgeBoundary = getMeasuredWidth() - getViewportOffsetX() - mEdgeSwipeRegionSize;
- if ((mDownMotionX <= leftEdgeBoundary || mDownMotionX >= rightEdgeBoundary)) {
- mDownEventOnEdge = true;
- }
+ saveDownState(ev);
if (mTouchState == TOUCH_STATE_SCROLLING) {
pageBeginMoving();
@@ -1479,8 +1510,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
removeCallbacks(mSidePageHoverRunnable);
mSidePageHoverIndex = -1;
}
- } else {
- determineScrollingStart(ev);
+ } else if (mIsCameraEvent || determineScrollingStart(ev)) {
+ startScrolling(ev);
}
break;
@@ -1604,7 +1635,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
private void resetTouchState() {
releaseVelocityTracker();
endReordering();
- mTouchState = TOUCH_STATE_REST;
+ setTouchState(TOUCH_STATE_REST);
mActivePointerId = INVALID_POINTER;
mDownEventOnEdge = false;
}
@@ -1821,8 +1852,17 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
protected void snapToPage(int whichPage, int delta, int duration) {
snapToPage(whichPage, delta, duration, false);
}
+
protected void snapToPage(int whichPage, int delta, int duration, boolean immediate) {
- mNextPage = whichPage;
+ if (mPageSwapIndex != -1 && whichPage == mPageSwapIndex) {
+ // jump to the last page
+ mNextPage = getPageCount() - 1;
+ if (DEBUG_WARP) Log.v(TAG, "snapToPage(" + whichPage + ") : reset mPageSwapIndex");
+ mPageSwapIndex = -1;
+ } else {
+ mNextPage = whichPage;
+ }
+
notifyPageSwitching(whichPage);
View focusedChild = getFocusedChild();
if (focusedChild != null && whichPage != mCurrentPage &&
@@ -2102,7 +2142,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
// Set the touch state to reordering (allows snapping to pages, dragging a child, etc.)
- mTouchState = TOUCH_STATE_REORDERING;
+ setTouchState(TOUCH_STATE_REORDERING);
mIsReordering = true;
// Mark all the non-widget pages as invisible
@@ -2564,4 +2604,46 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
public boolean onHoverEvent(android.view.MotionEvent event) {
return true;
}
+
+ void beginCameraEvent() {
+ mIsCameraEvent = true;
+ }
+
+ void endCameraEvent() {
+ mIsCameraEvent = false;
+ }
+
+ /**
+ * Swaps the position of the views by setting the left and right edges appropriately.
+ */
+ void swapPages(int indexA, int indexB) {
+ View viewA = getPageAt(indexA);
+ View viewB = getPageAt(indexB);
+ if (viewA != viewB && viewA != null && viewB != null) {
+ int deltaX = viewA.getLeft() - viewB.getLeft();
+ viewA.offsetLeftAndRight(-deltaX);
+ viewB.offsetLeftAndRight(deltaX);
+ }
+ }
+
+ public void startWarp(int pageIndex) {
+ if (DEBUG_WARP) Log.v(TAG, "START WARP");
+ if (pageIndex != mCurrentPage + 1) {
+ mPageSwapIndex = mCurrentPage + 1;
+ }
+ }
+
+ public void endWarp() {
+ if (DEBUG_WARP) Log.v(TAG, "END WARP");
+ // mPageSwapIndex is reset in snapToPage() after the scroll animation completes
+ }
+
+ public void onPageBeginWarp() {
+
+ }
+
+ public void onPageEndWarp() {
+
+ }
+
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index fa5c769..fb73d39 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -52,7 +52,7 @@
<uses-permission android:name="android.permission.START_ANY_ACTIVITY" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" />
-
+
<!-- WindowManager -->
<uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
@@ -68,6 +68,9 @@
<!-- Alarm clocks -->
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
+ <!-- Keyguard -->
+ <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
+
<application
android:persistent="true"
android:allowClearUserData="false"
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png
new file mode 100644
index 0000000..0bb590e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png
new file mode 100644
index 0000000..b767098
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png
new file mode 100644
index 0000000..ea93f1a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png
new file mode 100644
index 0000000..cda7d4b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index 09923a7..0421910 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -145,15 +145,30 @@
/>
</LinearLayout>
- <com.android.systemui.statusbar.policy.KeyButtonView
- android:layout_width="80dp"
- android:id="@+id/search_light"
- android:layout_height="match_parent"
- android:layout_gravity="center_horizontal"
- android:src="@drawable/search_light"
- android:scaleType="center"
- android:visibility="gone"
- />
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:layout_width="80dp"
+ android:id="@+id/search_light"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:src="@drawable/search_light"
+ android:scaleType="center"
+ android:visibility="gone"
+ />
+
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/camera_button"
+ android:layout_height="match_parent"
+ android:layout_width="80dp"
+ android:layout_gravity="center_vertical|right"
+ android:src="@drawable/ic_sysbar_camera"
+ android:scaleType="center"
+ android:visibility="gone"
+ />
+ </FrameLayout>
<com.android.systemui.statusbar.policy.DeadZone
android:id="@+id/deadzone"
@@ -299,6 +314,8 @@
android:visibility="gone"
/>
+ <!-- No camera button in landscape mode -->
+
<com.android.systemui.statusbar.policy.DeadZone
android:id="@+id/deadzone"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
new file mode 100644
index 0000000..a6e2347
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2013 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.statusbar.phone;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.internal.policy.IKeyguardExitCallback;
+import com.android.internal.policy.IKeyguardShowCallback;
+import com.android.internal.policy.IKeyguardService;
+
+
+/**
+ * Facilitates event communication between navigation bar and keyguard. Currently used to
+ * control WidgetPager in keyguard to expose the camera widget.
+ *
+ */
+public class KeyguardTouchDelegate {
+ // TODO: propagate changes to these to {@link KeyguardServiceDelegate}
+ static final String KEYGUARD_PACKAGE = "com.android.keyguard";
+ static final String KEYGUARD_CLASS = "com.android.keyguard.KeyguardService";
+
+ IKeyguardService mService;
+
+ protected static final boolean DEBUG = false;
+ protected static final String TAG = "KeyguardTouchDelegate";
+
+ private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.v(TAG, "Connected to keyguard");
+ mService = IKeyguardService.Stub.asInterface(service);
+
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.v(TAG, "Disconnected from keyguard");
+ mService = null;
+ }
+
+ };
+
+ public KeyguardTouchDelegate(Context context) {
+ Intent intent = new Intent();
+ intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
+ if (!context.bindServiceAsUser(intent, mKeyguardConnection,
+ Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
+ if (DEBUG) Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
+ } else {
+ if (DEBUG) Log.v(TAG, "*** Keyguard started");
+ }
+ }
+
+ public boolean isSecure() {
+ boolean secure = false;
+ if (mService != null) {
+ try {
+ secure = mService.isSecure();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException calling keyguard.isSecure()!", e);
+ }
+ } else {
+ Log.w(TAG, "isSecure(): NO SERVICE!");
+ }
+ return secure;
+ }
+
+ public boolean dispatch(MotionEvent event) {
+ if (mService != null) {
+ try {
+ mService.dispatch(event);
+ } catch (RemoteException e) {
+ // What to do?
+ Log.e(TAG, "RemoteException sending event to keyguard!", e);
+ return false;
+ }
+ return true;
+ } else {
+ Log.w(TAG, "dispatch(event): NO SERVICE!");
+ }
+ return false;
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index 085130b..531a2fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -87,6 +87,7 @@ public final class NavigationBarTransitions extends BarTransitions {
setKeyButtonViewQuiescentAlpha(mView.getHomeButton(), alpha, animate);
setKeyButtonViewQuiescentAlpha(mView.getRecentsButton(), alpha, animate);
setKeyButtonViewQuiescentAlpha(mView.getMenuButton(), alpha, animate);
+ setKeyButtonViewQuiescentAlpha(mView.getCameraButton(), alpha, animate);
// apply to lights out
applyLightsOut(mode == MODE_LIGHTS_OUT, animate, force);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index b56d7be..3c6faae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -17,14 +17,20 @@
package com.android.systemui.statusbar.phone;
import android.animation.LayoutTransition;
+import android.app.ActivityManagerNative;
import android.app.StatusBarManager;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
+import android.os.RemoteException;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
@@ -77,6 +83,17 @@ public class NavigationBarView extends LinearLayout {
final static boolean WORKAROUND_INVALID_LAYOUT = true;
final static int MSG_CHECK_INVALID_LAYOUT = 8686;
+ // used to disable the camera icon in navbar when disabled by DPM
+ private boolean mCameraDisabledByDpm;
+ KeyguardTouchDelegate mTouchDelegate;
+
+ private final OnTouchListener mCameraTouchListener = new OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ return mTouchDelegate.dispatch(event);
+ }
+ };
+
private class H extends Handler {
public void handleMessage(Message m) {
switch (m.what) {
@@ -115,6 +132,26 @@ public class NavigationBarView extends LinearLayout {
getIcons(res);
mBarTransitions = new NavigationBarTransitions(this);
+
+ mTouchDelegate = new KeyguardTouchDelegate(mContext);
+
+ mCameraDisabledByDpm = isCameraDisabledByDpm();
+ watchForDevicePolicyChanges();
+ }
+
+ private void watchForDevicePolicyChanges() {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ mCameraDisabledByDpm = isCameraDisabledByDpm();
+ }
+ });
+ }
+ }, filter);
}
public BarTransitions getBarTransitions() {
@@ -173,6 +210,11 @@ public class NavigationBarView extends LinearLayout {
return mCurrentView.findViewById(R.id.search_light);
}
+ // shown when keyguard is visible and camera is available
+ public View getCameraButton() {
+ return mCurrentView.findViewById(R.id.camera_button);
+ }
+
private void getIcons(Resources res) {
mBackIcon = res.getDrawable(R.drawable.ic_sysbar_back);
mBackLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_land);
@@ -259,7 +301,31 @@ public class NavigationBarView extends LinearLayout {
getHomeButton() .setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
- getSearchLight().setVisibility((disableHome && !disableSearch) ? View.VISIBLE : View.GONE);
+ final boolean shouldShowSearch = disableHome && !disableSearch;
+ getSearchLight().setVisibility(shouldShowSearch ? View.VISIBLE : View.GONE);
+ final View cameraButton = getCameraButton();
+ if (cameraButton != null) {
+ cameraButton.setVisibility(
+ shouldShowSearch && !mCameraDisabledByDpm ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ private boolean isCameraDisabledByDpm() {
+ final DevicePolicyManager dpm =
+ (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ if (dpm != null) {
+ try {
+ final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
+ final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
+ final boolean disabledBecauseKeyguardSecure =
+ (disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
+ && mTouchDelegate.isSecure();
+ return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't get userId", e);
+ }
+ }
+ return false;
}
public void setSlippery(boolean newSlippery) {
@@ -302,6 +368,14 @@ public class NavigationBarView extends LinearLayout {
: findViewById(R.id.rot270);
mCurrentView = mRotatedViews[Surface.ROTATION_0];
+
+ // Add a touch handler for camera icon for all view orientations.
+ for (int i = 0; i < mRotatedViews.length; i++) {
+ View cameraButton = mRotatedViews[i].findViewById(R.id.camera_button);
+ if (cameraButton != null) {
+ cameraButton.setOnTouchListener(mCameraTouchListener);
+ }
+ }
}
public boolean isVertical() {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
index 874076a..56a282b 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
@@ -29,8 +29,10 @@ import com.android.internal.widget.LockPatternUtils;
* local or remote instances of keyguard.
*/
public class KeyguardServiceDelegate {
- private static final String KEYGUARD_PACKAGE = "com.android.keyguard";
- private static final String KEYGUARD_CLASS = "com.android.keyguard.KeyguardService";
+ // TODO: propagate changes to these to {@link KeyguardTouchDelegate}
+ public static final String KEYGUARD_PACKAGE = "com.android.keyguard";
+ public static final String KEYGUARD_CLASS = "com.android.keyguard.KeyguardService";
+
private static final String TAG = "KeyguardServiceDelegate";
private static final boolean DEBUG = true;
protected KeyguardServiceWrapper mKeyguardService;
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
index 6b9c7df..b27584d 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
@@ -20,6 +20,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import android.view.MotionEvent;
import com.android.internal.policy.IKeyguardShowCallback;
import com.android.internal.policy.IKeyguardExitCallback;
@@ -187,6 +188,10 @@ public class KeyguardServiceWrapper implements IKeyguardService {
}
}
+ public void dispatch(MotionEvent event) {
+ // Not used by PhoneWindowManager. See code in {@link NavigationBarView}
+ }
+
@Override
public IBinder asBinder() {
return mService.asBinder();