summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJorim Jaggi <jjaggi@google.com>2014-05-02 23:03:34 +0200
committerJorim Jaggi <jjaggi@google.com>2014-05-06 13:56:44 +0200
commit97b63c4112dbeaeca438afb8cc12e8e6982dd1e4 (patch)
tree0ab9ff6b8fe1f563c393db2fa2bfe381b4501c6b
parentefc1a289c681cd2af03f6b1dfe3b44cf3d7e43b6 (diff)
downloadframeworks_base-97b63c4112dbeaeca438afb8cc12e8e6982dd1e4.zip
frameworks_base-97b63c4112dbeaeca438afb8cc12e8e6982dd1e4.tar.gz
frameworks_base-97b63c4112dbeaeca438afb8cc12e8e6982dd1e4.tar.bz2
Implement phone affordance on lockscreen.
Refactor the camera affordance into a reusable view. This change also swaps the asset for the camera affordance. Bug: 14488709 Change-Id: I0633614f6a1ea81faa37923f748af3c635e64a52
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_camera_alt_24dp.pngbin0 -> 407 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_phone_24dp.pngbin0 -> 444 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.pngbin1517 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_camera_alt_24dp.pngbin0 -> 286 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_phone_24dp.pngbin0 -> 333 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.pngbin1060 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_camera_alt_24dp.pngbin0 -> 486 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_phone_24dp.pngbin0 -> 530 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.pngbin1998 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_camera_alt_24dp.pngbin0 -> 736 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_phone_24dp.pngbin0 -> 736 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.pngbin4172 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/ic_camera_alt_24dp.pngbin0 -> 930 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/ic_phone_24dp.pngbin0 -> 904 bytes
-rw-r--r--packages/SystemUI/res/layout/keyguard_bottom_area.xml26
-rw-r--r--packages/SystemUI/res/values/attrs.xml6
-rw-r--r--packages/SystemUI/res/values/dimens.xml4
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java136
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SwipeAffordanceView.java222
22 files changed, 336 insertions, 101 deletions
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_camera_alt_24dp.png b/packages/SystemUI/res/drawable-hdpi/ic_camera_alt_24dp.png
new file mode 100644
index 0000000..253c737
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_camera_alt_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_phone_24dp.png b/packages/SystemUI/res/drawable-hdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..a6a6448
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_phone_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png
deleted file mode 100644
index c6f03c4..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_camera_alt_24dp.png b/packages/SystemUI/res/drawable-mdpi/ic_camera_alt_24dp.png
new file mode 100644
index 0000000..ee1187b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_camera_alt_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_phone_24dp.png b/packages/SystemUI/res/drawable-mdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..2286bb4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_phone_24dp.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
deleted file mode 100644
index 1c2d7aa..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_camera_alt_24dp.png b/packages/SystemUI/res/drawable-xhdpi/ic_camera_alt_24dp.png
new file mode 100644
index 0000000..268eba0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_camera_alt_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_phone_24dp.png b/packages/SystemUI/res/drawable-xhdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..cd9ff60
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_phone_24dp.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
deleted file mode 100644
index fbd4d6b..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_camera_alt_24dp.png b/packages/SystemUI/res/drawable-xxhdpi/ic_camera_alt_24dp.png
new file mode 100644
index 0000000..9175118
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_camera_alt_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_phone_24dp.png b/packages/SystemUI/res/drawable-xxhdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..3c546e5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_phone_24dp.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
deleted file mode 100644
index 86df881..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_camera_alt_24dp.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_camera_alt_24dp.png
new file mode 100644
index 0000000..20e26b8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_camera_alt_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_phone_24dp.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..4f7da0a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_phone_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 809adcd..ec5acba 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -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"
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 734abdc..f5674d2 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -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" />
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1900fea..28de6ac 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -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>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b4a13d4..3f0a60f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -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>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
new file mode 100644
index 0000000..5bc7e5a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
@@ -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);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 3cc22ef..58b3f2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -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;
- }
- };
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 0db6914..80eff13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -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.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SwipeAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SwipeAffordanceView.java
new file mode 100644
index 0000000..049c5fc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SwipeAffordanceView.java
@@ -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);
+ }
+}