/*
 * 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.systemui.statusbar;

import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;

/**
 * The guts of a notification revealed when performing a long press.
 */
public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsContent {
    private static final String TAG = "AppOpsGuts";

    private PackageManager mPm;

    private String mPkg;
    private String mAppName;
    private int mAppUid;
    private StatusBarNotification mSbn;
    private ArraySet<Integer> mAppOps;
    private MetricsLogger mMetricsLogger;
    private OnSettingsClickListener mOnSettingsClickListener;
    private NotificationGuts mGutsContainer;

    private OnClickListener mOnOk = v -> {
        closeControls(v);
    };

    public AppOpsInfo(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public interface OnSettingsClickListener {
        void onClick(View v, String pkg, int uid, ArraySet<Integer> ops);
    }

    public void bindGuts(final PackageManager pm,
            final OnSettingsClickListener onSettingsClick,
            final StatusBarNotification sbn,
            ArraySet<Integer> activeOps) {
        mPkg = sbn.getPackageName();
        mSbn = sbn;
        mPm = pm;
        mAppName = mPkg;
        mOnSettingsClickListener = onSettingsClick;
        mAppOps = activeOps;

        bindHeader();
        bindPrompt();
        bindButtons();

        mMetricsLogger = new MetricsLogger();
        mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, true);
    }

    private void bindHeader() {
        // Package name
        Drawable pkgicon = null;
        ApplicationInfo info;
        try {
            info = mPm.getApplicationInfo(mPkg,
                    PackageManager.MATCH_UNINSTALLED_PACKAGES
                            | PackageManager.MATCH_DISABLED_COMPONENTS
                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                            | PackageManager.MATCH_DIRECT_BOOT_AWARE);
            if (info != null) {
                mAppUid = mSbn.getUid();
                mAppName = String.valueOf(mPm.getApplicationLabel(info));
                pkgicon = mPm.getApplicationIcon(info);
            }
        } catch (PackageManager.NameNotFoundException e) {
            // app is gone, just show package name and generic icon
            pkgicon = mPm.getDefaultActivityIcon();
        }
        ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
        ((TextView) findViewById(R.id.pkgname)).setText(mAppName);
    }

    private void bindPrompt() {
        final TextView prompt = findViewById(R.id.prompt);
        prompt.setText(getPrompt());
    }

    private void bindButtons() {
        View settings =  findViewById(R.id.settings);
        settings.setOnClickListener((View view) -> {
            mOnSettingsClickListener.onClick(view, mPkg, mAppUid, mAppOps);
        });
        TextView ok = findViewById(R.id.ok);
        ok.setOnClickListener(mOnOk);
    }

    private String getPrompt() {
        if (mAppOps == null || mAppOps.size() == 0) {
            return "";
        } else if (mAppOps.size() == 1) {
            if (mAppOps.contains(AppOpsManager.OP_CAMERA)) {
                return mContext.getString(R.string.appops_camera);
            } else if (mAppOps.contains(AppOpsManager.OP_RECORD_AUDIO)) {
                return mContext.getString(R.string.appops_microphone);
            } else {
                return mContext.getString(R.string.appops_overlay);
            }
        } else if (mAppOps.size() == 2) {
            if (mAppOps.contains(AppOpsManager.OP_CAMERA)) {
                if (mAppOps.contains(AppOpsManager.OP_RECORD_AUDIO)) {
                    return mContext.getString(R.string.appops_camera_mic);
                } else {
                    return mContext.getString(R.string.appops_camera_overlay);
                }
            } else {
                return mContext.getString(R.string.appops_mic_overlay);
            }
        } else {
            return mContext.getString(R.string.appops_camera_mic_overlay);
        }
    }

    @Override
    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
        super.onInitializeAccessibilityEvent(event);
        if (mGutsContainer != null &&
                event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
            if (mGutsContainer.isExposed()) {
                event.getText().add(mContext.getString(
                        R.string.notification_channel_controls_opened_accessibility, mAppName));
            } else {
                event.getText().add(mContext.getString(
                        R.string.notification_channel_controls_closed_accessibility, mAppName));
            }
        }
    }

    private void closeControls(View v) {
        mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false);
        int[] parentLoc = new int[2];
        int[] targetLoc = new int[2];
        mGutsContainer.getLocationOnScreen(parentLoc);
        v.getLocationOnScreen(targetLoc);
        final int centerX = v.getWidth() / 2;
        final int centerY = v.getHeight() / 2;
        final int x = targetLoc[0] - parentLoc[0] + centerX;
        final int y = targetLoc[1] - parentLoc[1] + centerY;
        mGutsContainer.closeControls(x, y, false, false);
    }

    @Override
    public void setGutsParent(NotificationGuts guts) {
        mGutsContainer = guts;
    }

    @Override
    public boolean willBeRemoved() {
        return false;
    }

    @Override
    public boolean shouldBeSaved() {
        return false;
    }

    @Override
    public View getContentView() {
        return this;
    }

    @Override
    public boolean handleCloseControls(boolean save, boolean force) {
        return false;
    }

    @Override
    public int getActualHeight() {
        return getHeight();
    }
}
