am 6ea37298: Merge "Implement phone affordance on lockscreen."

* commit '6ea372988f0732183590c021c65d392bf419dafd':
  Implement phone affordance on lockscreen.
This commit is contained in:
Jorim Jaggi
2014-05-06 12:12:35 +00:00
committed by Android Git Automerger
22 changed files with 336 additions and 101 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 530 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 904 B

View File

@@ -22,15 +22,29 @@
android:layout_height="match_parent"
android:layout_width="match_parent"
>
<com.android.systemui.statusbar.policy.KeyButtonView
<com.android.systemui.statusbar.phone.SwipeAffordanceView
android:id="@+id/camera_button"
android:layout_height="80dp"
android:layout_width="80dp"
android:layout_gravity="bottom|right"
android:src="@drawable/ic_sysbar_camera"
android:layout_height="64dp"
android:layout_width="64dp"
android:layout_gravity="bottom|end"
android:tint="#ffffffff"
android:src="@drawable/ic_camera_alt_24dp"
android:scaleType="center"
android:contentDescription="@string/accessibility_camera_button"
systemui:glowBackground="@drawable/ic_sysbar_highlight_land" />
systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
systemui:swipeDirection="start"/>
<com.android.systemui.statusbar.phone.SwipeAffordanceView
android:id="@+id/phone_button"
android:layout_height="64dp"
android:layout_width="64dp"
android:layout_gravity="bottom|start"
android:tint="#ffffffff"
android:src="@drawable/ic_phone_24dp"
android:scaleType="center"
android:contentDescription="@string/accessibility_phone_button"
systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
systemui:swipeDirection="end"/>
<com.android.systemui.statusbar.phone.KeyguardIndicationTextView
android:id="@+id/keyguard_indication_text"

View File

@@ -45,6 +45,12 @@
<declare-styleable name="BatteryMeterView">
<attr name="frameColor" format="color" />
</declare-styleable>
<declare-styleable name="SwipeAffordanceView">
<attr name="swipeDirection" format="enum">
<enum name="start" value="0" />
<enum name="end" value="1" />
</attr>
</declare-styleable>
<attr name="orientation">
<enum name="horizontal" value="0" />
<enum name="vertical" value="1" />

View File

@@ -258,8 +258,8 @@
<!-- Width of the zen mode interstitial dialog. -->
<dimen name="zen_mode_dialog_width">320dp</dimen>
<!-- Camera affordance drag distance -->
<dimen name="camera_drag_distance">100dp</dimen>
<!-- Lockscreen affordance drag distance for camera and phone. -->
<dimen name="affordance_drag_distance">100dp</dimen>
<dimen name="quick_settings_tmp_scrim_stroke_width">8dp</dimen>
<dimen name="quick_settings_tmp_scrim_text_size">30dp</dimen>

View File

@@ -196,6 +196,8 @@
<string name="accessibility_search_light">Search</string>
<!-- Content description of the camera button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_camera_button">Camera</string>
<!-- Content description of the phone button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_phone_button">Phone</string>
<!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_ime_switch_button">Switch input method button.</string>

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.statusbar.phone;
import android.content.Intent;
/**
* An interface to start activities. This is used to as a callback from the views to
* {@link PhoneStatusBar} to allow custom handling for starting the activity, i.e. dismissing the
* Keyguard.
*/
public interface ActivityStarter {
public void startActivity(Intent intent);
}

View File

@@ -22,6 +22,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -42,14 +43,18 @@ import com.android.systemui.R;
* Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
* text.
*/
public class KeyguardBottomAreaView extends FrameLayout {
public class KeyguardBottomAreaView extends FrameLayout
implements SwipeAffordanceView.AffordanceListener {
final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView";
private View mCameraButton;
private float mCameraDragDistance;
private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL);
private SwipeAffordanceView mCameraButton;
private SwipeAffordanceView mPhoneButton;
private PowerManager mPowerManager;
private int mScaledTouchSlop;
private ActivityStarter mActivityStarter;
public KeyguardBottomAreaView(Context context) {
super(context);
@@ -71,20 +76,37 @@ public class KeyguardBottomAreaView extends FrameLayout {
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mCameraButton = findViewById(R.id.camera_button);
mCameraButton = (SwipeAffordanceView) findViewById(R.id.camera_button);
mPhoneButton = (SwipeAffordanceView) findViewById(R.id.phone_button);
mCameraButton.setAffordanceListener(this);
mPhoneButton.setAffordanceListener(this);
watchForDevicePolicyChanges();
watchForAccessibilityChanges();
updateCameraVisibility();
mCameraDragDistance = getResources().getDimension(R.dimen.camera_drag_distance);
mScaledTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
updatePhoneVisibility();
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
}
public void setActivityStarter(ActivityStarter activityStarter) {
mActivityStarter = activityStarter;
}
private void updateCameraVisibility() {
boolean visible = !isCameraDisabledByDpm();
mCameraButton.setVisibility(visible ? View.VISIBLE : View.GONE);
}
private void updatePhoneVisibility() {
boolean visible = isPhoneVisible();
mPhoneButton.setVisibility(visible ? View.VISIBLE : View.GONE);
}
private boolean isPhoneVisible() {
PackageManager pm = mContext.getPackageManager();
return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
&& pm.resolveActivity(PHONE_INTENT, 0) != null;
}
private boolean isCameraDisabledByDpm() {
final DevicePolicyManager dpm =
(DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
@@ -136,15 +158,8 @@ public class KeyguardBottomAreaView extends FrameLayout {
}
private void enableAccessibility(boolean touchExplorationEnabled) {
// Add a touch handler or accessibility click listener for camera button.
if (touchExplorationEnabled) {
mCameraButton.setOnTouchListener(null);
mCameraButton.setOnClickListener(mCameraClickListener);
} else {
mCameraButton.setOnTouchListener(mCameraTouchListener);
mCameraButton.setOnClickListener(null);
}
mCameraButton.enableAccessibility(touchExplorationEnabled);
mPhoneButton.enableAccessibility(touchExplorationEnabled);
}
private void launchCamera() {
@@ -153,80 +168,21 @@ public class KeyguardBottomAreaView extends FrameLayout {
UserHandle.CURRENT);
}
private final OnClickListener mCameraClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
private void launchPhone() {
mActivityStarter.startActivity(PHONE_INTENT);
}
@Override
public void onUserActivity(long when) {
mPowerManager.userActivity(when, false);
}
@Override
public void onActionPerformed(SwipeAffordanceView view) {
if (view == mCameraButton) {
launchCamera();
} else if (view == mPhoneButton) {
launchPhone();
}
};
private final OnTouchListener mCameraTouchListener = new OnTouchListener() {
private float mStartX;
private boolean mTouchSlopReached;
private boolean mSkipCancelAnimation;
@Override
public boolean onTouch(final View cameraButtonView, MotionEvent event) {
float realX = event.getRawX();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mStartX = realX;
mTouchSlopReached = false;
mSkipCancelAnimation = false;
break;
case MotionEvent.ACTION_MOVE:
if (realX > mStartX) {
realX = mStartX;
}
if (realX < mStartX - mCameraDragDistance) {
cameraButtonView.setPressed(true);
mPowerManager.userActivity(event.getEventTime(), false);
} else {
cameraButtonView.setPressed(false);
}
if (realX < mStartX - mScaledTouchSlop) {
mTouchSlopReached = true;
}
cameraButtonView.setTranslationX(Math.max(realX - mStartX,
-mCameraDragDistance));
break;
case MotionEvent.ACTION_UP:
if (realX < mStartX - mCameraDragDistance) {
launchCamera();
cameraButtonView.animate().x(-cameraButtonView.getWidth())
.setInterpolator(new AccelerateInterpolator(2f)).withEndAction(
new Runnable() {
@Override
public void run() {
cameraButtonView.setTranslationX(0);
}
});
mSkipCancelAnimation = true;
}
if (realX < mStartX - mScaledTouchSlop) {
mTouchSlopReached = true;
}
if (!mTouchSlopReached) {
mSkipCancelAnimation = true;
cameraButtonView.animate().translationX(-mCameraDragDistance / 2).
setInterpolator(new DecelerateInterpolator()).withEndAction(
new Runnable() {
@Override
public void run() {
cameraButtonView.animate().translationX(0).
setInterpolator(new AccelerateInterpolator());
}
});
}
case MotionEvent.ACTION_CANCEL:
cameraButtonView.setPressed(false);
if (!mSkipCancelAnimation) {
cameraButtonView.animate().translationX(0)
.setInterpolator(new AccelerateInterpolator(2f));
}
break;
}
return true;
}
};
}
}

View File

@@ -124,7 +124,7 @@ import java.util.Collection;
import java.util.Collections;
public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
DragDownHelper.OnDragDownListener {
DragDownHelper.OnDragDownListener, ActivityStarter {
static final String TAG = "PhoneStatusBar";
public static final boolean DEBUG = BaseStatusBar.DEBUG;
public static final boolean SPEW = false;
@@ -236,7 +236,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// top bar
View mNotificationPanelHeader;
View mKeyguardStatusView;
View mKeyguardBottomArea;
KeyguardBottomAreaView mKeyguardBottomArea;
boolean mLeaveOpenOnKeyguardHide;
KeyguardIndicationTextView mKeyguardIndicationTextView;
@@ -639,7 +639,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mNotificationPanelHeader = mStatusBarWindow.findViewById(R.id.header);
mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
mKeyguardBottomArea = mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
mKeyguardBottomArea =
(KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
mKeyguardBottomArea.setActivityStarter(this);
mKeyguardIndicationTextView = (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
R.id.keyguard_indication_text);
mClearButton = mStatusBarWindow.findViewById(R.id.clear_all_button);
@@ -1578,6 +1580,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return new PhoneStatusBar.H();
}
@Override
public void startActivity(Intent intent) {
startActivityDismissingKeyguard(intent, false);
}
/**
* All changes to the status bar and notifications funnel through here and are batched.
*/

View File

@@ -0,0 +1,222 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.statusbar.phone;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.Button;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.KeyButtonView;
/**
* A swipeable button for affordances on the lockscreen. This is used for the camera and phone
* affordance.
*/
public class SwipeAffordanceView extends KeyButtonView {
private static final int SWIPE_DIRECTION_START = 0;
private static final int SWIPE_DIRECTION_END = 1;
private static final int SWIPE_DIRECTION_LEFT = 0;
private static final int SWIPE_DIRECTION_RIGHT = 1;
private AffordanceListener mListener;
private int mScaledTouchSlop;
private float mDragDistance;
private int mResolvedSwipeDirection;
private int mSwipeDirection;
public SwipeAffordanceView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SwipeAffordanceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.SwipeAffordanceView,
0, 0);
try {
mSwipeDirection = a.getInt(R.styleable.SwipeAffordanceView_swipeDirection, 0);
} finally {
a.recycle();
}
}
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
super.onRtlPropertiesChanged(layoutDirection);
if (!isLayoutRtl()) {
mResolvedSwipeDirection = mSwipeDirection;
} else {
mResolvedSwipeDirection = mSwipeDirection == SWIPE_DIRECTION_START
? SWIPE_DIRECTION_RIGHT
: SWIPE_DIRECTION_LEFT;
}
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mDragDistance = getResources().getDimension(R.dimen.affordance_drag_distance);
mScaledTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
}
public void enableAccessibility(boolean touchExplorationEnabled) {
// Add a touch handler or accessibility click listener for camera button.
if (touchExplorationEnabled) {
setOnTouchListener(null);
setOnClickListener(mClickListener);
} else {
setOnTouchListener(mTouchListener);
setOnClickListener(null);
}
}
public void setAffordanceListener(AffordanceListener listener) {
mListener = listener;
}
private void onActionPerformed() {
if (mListener != null) {
mListener.onActionPerformed(this);
}
}
private void onUserActivity(long when) {
if (mListener != null) {
mListener.onUserActivity(when);
}
}
private final OnClickListener mClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
onActionPerformed();
}
};
private final OnTouchListener mTouchListener = new OnTouchListener() {
private float mStartX;
private boolean mTouchSlopReached;
private boolean mSkipCancelAnimation;
@Override
public boolean onTouch(final View view, MotionEvent event) {
float realX = event.getRawX();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mStartX = realX;
mTouchSlopReached = false;
mSkipCancelAnimation = false;
break;
case MotionEvent.ACTION_MOVE:
if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
? realX > mStartX
: realX < mStartX) {
realX = mStartX;
}
if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
? realX < mStartX - mDragDistance
: realX > mStartX + mDragDistance) {
view.setPressed(true);
onUserActivity(event.getEventTime());
} else {
view.setPressed(false);
}
if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
? realX < mStartX - mScaledTouchSlop
: realX > mStartX + mScaledTouchSlop) {
mTouchSlopReached = true;
}
view.setTranslationX(mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
? Math.max(realX - mStartX, -mDragDistance)
: Math.min(realX - mStartX, mDragDistance));
break;
case MotionEvent.ACTION_UP:
if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
? realX < mStartX - mDragDistance
: realX > mStartX + mDragDistance) {
onActionPerformed();
view.animate().x(mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
? -view.getWidth()
: ((View) view.getParent()).getWidth() + view.getWidth())
.setInterpolator(new AccelerateInterpolator(2f)).withEndAction(
new Runnable() {
@Override
public void run() {
view.setTranslationX(0);
}
});
mSkipCancelAnimation = true;
}
if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
? realX < mStartX - mScaledTouchSlop
: realX > mStartX + mScaledTouchSlop) {
mTouchSlopReached = true;
}
if (!mTouchSlopReached) {
mSkipCancelAnimation = true;
view.animate().translationX(mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
? -mDragDistance / 2
: mDragDistance / 2).
setInterpolator(new DecelerateInterpolator()).withEndAction(
new Runnable() {
@Override
public void run() {
view.animate().translationX(0).
setInterpolator(new AccelerateInterpolator());
}
});
}
case MotionEvent.ACTION_CANCEL:
view.setPressed(false);
if (!mSkipCancelAnimation) {
view.animate().translationX(0)
.setInterpolator(new AccelerateInterpolator(2f));
}
break;
}
return true;
}
};
public interface AffordanceListener {
/**
* Called when the view would like to report user activity.
*
* @param when The timestamp of the user activity in {@link SystemClock#uptimeMillis} time
* base.
*/
void onUserActivity(long when);
/**
* Called when the action of the affordance has been performed.
*/
void onActionPerformed(SwipeAffordanceView view);
}
}