Merge "Add camera affordance to navigation bar on phones" into klp-dev

This commit is contained in:
Jim Miller
2013-09-20 01:33:28 +00:00
committed by Android (Google) Code Review
23 changed files with 455 additions and 84 deletions

View File

@ -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);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -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);
}
}

View File

@ -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);
}
};
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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() {
}
}

View File

@ -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"

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -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"

View File

@ -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;
}
}

View File

@ -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;
}
};
}
}

View File

@ -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() {

View File

@ -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;

View File

@ -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();