blob: 3cc22efee2c02c33638de3c525c954c359691beb [file] [log] [blame]
/*
* 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.app.ActivityManagerNative;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.MediaStore;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
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 {
final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView";
private View mCameraButton;
private float mCameraDragDistance;
private PowerManager mPowerManager;
private int mScaledTouchSlop;
public KeyguardBottomAreaView(Context context) {
super(context);
}
public KeyguardBottomAreaView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mCameraButton = findViewById(R.id.camera_button);
watchForDevicePolicyChanges();
watchForAccessibilityChanges();
updateCameraVisibility();
mCameraDragDistance = getResources().getDimension(R.dimen.camera_drag_distance);
mScaledTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
}
private void updateCameraVisibility() {
boolean visible = !isCameraDisabledByDpm();
mCameraButton.setVisibility(visible ? View.VISIBLE : View.GONE);
}
private boolean isCameraDisabledByDpm() {
final DevicePolicyManager dpm =
(DevicePolicyManager) getContext().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
&& KeyguardTouchDelegate.getInstance(getContext()).isSecure();
return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
} catch (RemoteException e) {
Log.e(TAG, "Can't get userId", e);
}
}
return false;
}
private void watchForDevicePolicyChanges() {
final IntentFilter filter = new IntentFilter();
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
getContext().registerReceiver(new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
post(new Runnable() {
@Override
public void run() {
updateCameraVisibility();
}
});
}
}, filter);
}
private void watchForAccessibilityChanges() {
final AccessibilityManager am =
(AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
// Set the initial state
enableAccessibility(am.isTouchExplorationEnabled());
// Watch for changes
am.addTouchExplorationStateChangeListener(
new AccessibilityManager.TouchExplorationStateChangeListener() {
@Override
public void onTouchExplorationStateChanged(boolean enabled) {
enableAccessibility(enabled);
}
});
}
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);
}
}
private void launchCamera() {
mContext.startActivityAsUser(
new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE),
UserHandle.CURRENT);
}
private final OnClickListener mCameraClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
launchCamera();
}
};
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;
}
};
}