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