Merge "Add camera affordance to navigation bar on phones" into klp-dev
@ -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);
|
||||
}
|
||||
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 591 B |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 535 B |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 621 B |
BIN
packages/Keyguard/res/drawable-xxhdpi/kg_widget_bg_padded.9.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -185,6 +185,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()) {
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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"
|
||||
|
BIN
packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -67,6 +67,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);
|
||||
@ -140,4 +141,4 @@ public final class NavigationBarTransitions extends BarTransitions {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|