blob: a62edfd44ee8906cc0b12262e7a90b2172132447 [file] [log] [blame]
/*
* Copyright (C) 2018 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.phone;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.os.UserManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
import com.android.internal.util.UserIcons;
import java.util.List;
/**
* EmergencyInfoGroup display user icon and user name. And it is an entry point to
* Emergency Information.
*/
public class EmergencyInfoGroup extends FrameLayout implements View.OnClickListener {
// Time to hide view of confirmation.
private static final long HIDE_DELAY_MS = 3000;
private static final int[] ICON_VIEWS =
{R.id.emergency_info_image, R.id.confirmed_emergency_info_image};
private TextView mEmergencyInfoName;
private View mEmergencyInfoButton;
private View mEmergencyInfoConfirmButton;
private MotionEvent mPendingTouchEvent;
private OnConfirmClickListener mOnConfirmClickListener;
private boolean mConfirmViewHiding;
public EmergencyInfoGroup(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
/**
* Interface definition for a callback to be invoked when the view of confirmation on emergency
* info button is clicked.
*/
public interface OnConfirmClickListener {
/**
* Called when the view of confirmation on emergency info button has been clicked.
*
* @param button The shortcut button that was clicked.
*/
void onConfirmClick(EmergencyInfoGroup button);
}
/**
* Register a callback {@link OnConfirmClickListener} to be invoked when view of confirmation
* is clicked.
*
* @param onConfirmClickListener The callback that will run.
*/
public void setOnConfirmClickListener(OnConfirmClickListener onConfirmClickListener) {
mOnConfirmClickListener = onConfirmClickListener;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mEmergencyInfoButton = findViewById(R.id.emergency_info_view);
mEmergencyInfoName = (TextView) findViewById(R.id.emergency_info_name);
mEmergencyInfoConfirmButton = findViewById(R.id.emergency_info_confirm_view);
mEmergencyInfoButton.setOnClickListener(this);
mEmergencyInfoConfirmButton.setOnClickListener(this);
mConfirmViewHiding = true;
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
if (visibility == View.VISIBLE) {
setupButtonInfo();
}
}
private void setupButtonInfo() {
List<ResolveInfo> infos;
if (TelephonyManager.EMERGENCY_ASSISTANCE_ENABLED) {
infos = EmergencyAssistanceHelper.resolveAssistPackageAndQueryActivities(getContext());
} else {
infos = null;
}
boolean visible = false;
if (infos != null && infos.size() > 0) {
final String packageName = infos.get(0).activityInfo.packageName;
final Intent intent = new Intent(
EmergencyAssistanceHelper.getIntentAction())
.setPackage(packageName);
setTag(R.id.tag_intent, intent);
setUserIcon();
visible = true;
}
mEmergencyInfoName.setText(getUserName());
setVisibility(visible ? View.VISIBLE : View.GONE);
}
private void setUserIcon() {
for (int iconView : ICON_VIEWS) {
ImageView userIcon = findViewById(iconView);
userIcon.setImageDrawable(getCircularUserIcon());
}
}
/**
* Get user icon.
*
* @return user icon, or default user icon if user do not set photo.
*/
private Drawable getCircularUserIcon() {
final UserManager userManager = (UserManager) getContext().getSystemService(
Context.USER_SERVICE);
Bitmap bitmapUserIcon = userManager.getUserIcon();
if (bitmapUserIcon == null) {
// get default user icon.
final Drawable defaultUserIcon = UserIcons.getDefaultUserIcon(
getContext().getResources(), UserHandle.myUserId(), false);
bitmapUserIcon = UserIcons.convertToBitmap(defaultUserIcon);
}
RoundedBitmapDrawable drawableUserIcon = RoundedBitmapDrawableFactory.create(
getContext().getResources(), bitmapUserIcon);
drawableUserIcon.setCircular(true);
return drawableUserIcon;
}
private CharSequence getUserName() {
final UserManager userManager = (UserManager) getContext().getSystemService(
Context.USER_SERVICE);
final String userName = userManager.getUserName();
return TextUtils.isEmpty(userName) ? getContext().getText(
R.string.emergency_information_owner_hint) : userName;
}
/**
* Called by the activity before a touch event is dispatched to the view hierarchy.
*/
public void onPreTouchEvent(MotionEvent event) {
mPendingTouchEvent = event;
}
/**
* Called by the activity after a touch event is dispatched to the view hierarchy.
*/
public void onPostTouchEvent(MotionEvent event) {
// Hide the confirmation button if a touch event was delivered to the activity but not to
// this view.
if (mPendingTouchEvent != null) {
hideSelectedButton();
}
mPendingTouchEvent = null;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
boolean handled = super.dispatchTouchEvent(event);
if (mPendingTouchEvent == event && handled) {
mPendingTouchEvent = null;
}
return handled;
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.emergency_info_view) {
AccessibilityManager accessibilityMgr =
(AccessibilityManager) getContext().getSystemService(
Context.ACCESSIBILITY_SERVICE);
if (accessibilityMgr.isTouchExplorationEnabled()) {
if (mOnConfirmClickListener != null) {
mOnConfirmClickListener.onConfirmClick(this);
}
} else {
revealSelectedButton();
}
} else if (view.getId() == R.id.emergency_info_confirm_view) {
if (mOnConfirmClickListener != null) {
mOnConfirmClickListener.onConfirmClick(this);
}
}
}
private void revealSelectedButton() {
mConfirmViewHiding = false;
mEmergencyInfoConfirmButton.setVisibility(View.VISIBLE);
int centerX = mEmergencyInfoButton.getLeft() + mEmergencyInfoButton.getWidth() / 2;
int centerY = mEmergencyInfoButton.getTop() + mEmergencyInfoButton.getHeight() / 2;
Animator reveal = ViewAnimationUtils.createCircularReveal(
mEmergencyInfoConfirmButton,
centerX,
centerY,
0,
Math.max(centerX, mEmergencyInfoConfirmButton.getWidth() - centerX)
+ Math.max(centerY, mEmergencyInfoConfirmButton.getHeight() - centerY));
reveal.start();
postDelayed(mCancelSelectedButtonRunnable, HIDE_DELAY_MS);
mEmergencyInfoConfirmButton.requestFocus();
}
private void hideSelectedButton() {
if (mConfirmViewHiding || mEmergencyInfoConfirmButton.getVisibility() != VISIBLE) {
return;
}
mConfirmViewHiding = true;
removeCallbacks(mCancelSelectedButtonRunnable);
int centerX =
mEmergencyInfoConfirmButton.getLeft() + mEmergencyInfoConfirmButton.getWidth() / 2;
int centerY =
mEmergencyInfoConfirmButton.getTop() + mEmergencyInfoConfirmButton.getHeight() / 2;
Animator reveal = ViewAnimationUtils.createCircularReveal(
mEmergencyInfoConfirmButton,
centerX,
centerY,
Math.max(centerX, mEmergencyInfoButton.getWidth() - centerX)
+ Math.max(centerY, mEmergencyInfoButton.getHeight() - centerY),
0);
reveal.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mEmergencyInfoConfirmButton.setVisibility(INVISIBLE);
}
});
reveal.start();
mEmergencyInfoButton.requestFocus();
}
private final Runnable mCancelSelectedButtonRunnable = new Runnable() {
@Override
public void run() {
if (!isAttachedToWindow()) return;
hideSelectedButton();
}
};
}