/*
 * 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.internal.app;

import static android.content.res.ResourceId.ID_NULL;

import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Slog;
import android.view.WindowManager;

import com.android.internal.R;

public class SuspendedAppActivity extends AlertActivity
        implements DialogInterface.OnClickListener {
    private static final String TAG = SuspendedAppActivity.class.getSimpleName();
    private static final String PACKAGE_NAME = "com.android.internal.app";

    public static final String EXTRA_SUSPENDED_PACKAGE = PACKAGE_NAME + ".extra.SUSPENDED_PACKAGE";
    public static final String EXTRA_SUSPENDING_PACKAGE =
            PACKAGE_NAME + ".extra.SUSPENDING_PACKAGE";
    public static final String EXTRA_DIALOG_INFO = PACKAGE_NAME + ".extra.DIALOG_INFO";

    private Intent mMoreDetailsIntent;
    private int mUserId;
    private PackageManager mPm;
    private Resources mSuspendingAppResources;
    private SuspendDialogInfo mSuppliedDialogInfo;

    private CharSequence getAppLabel(String packageName) {
        try {
            return mPm.getApplicationInfoAsUser(packageName, 0, mUserId).loadLabel(mPm);
        } catch (PackageManager.NameNotFoundException ne) {
            Slog.e(TAG, "Package " + packageName + " not found", ne);
        }
        return packageName;
    }

    private Intent getMoreDetailsActivity(String suspendingPackage, String suspendedPackage,
            int userId) {
        final Intent moreDetailsIntent = new Intent(Intent.ACTION_SHOW_SUSPENDED_APP_DETAILS)
                .setPackage(suspendingPackage);
        final String requiredPermission = Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS;
        final ResolveInfo resolvedInfo = mPm.resolveActivityAsUser(moreDetailsIntent, 0, userId);
        if (resolvedInfo != null && resolvedInfo.activityInfo != null
                && requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
            moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
            return moreDetailsIntent;
        }
        return null;
    }

    private Drawable resolveIcon() {
        final int iconId = (mSuppliedDialogInfo != null) ? mSuppliedDialogInfo.getIconResId()
                : ID_NULL;
        if (iconId != ID_NULL && mSuspendingAppResources != null) {
            try {
                return mSuspendingAppResources.getDrawable(iconId, null);
            } catch (Resources.NotFoundException nfe) {
                Slog.e(TAG, "Could not resolve drawable resource id " + iconId);
            }
        }
        return null;
    }

    private String resolveTitle() {
        final int titleId = (mSuppliedDialogInfo != null) ? mSuppliedDialogInfo.getTitleResId()
                : ID_NULL;
        if (titleId != ID_NULL && mSuspendingAppResources != null) {
            try {
                return mSuspendingAppResources.getString(titleId);
            } catch (Resources.NotFoundException nfe) {
                Slog.e(TAG, "Could not resolve string resource id " + titleId);
            }
        }
        return getString(R.string.app_suspended_title);
    }

    private String resolveDialogMessage(String suspendingPkg, String suspendedPkg) {
        final CharSequence suspendedAppLabel = getAppLabel(suspendedPkg);
        if (mSuppliedDialogInfo != null) {
            final int messageId = mSuppliedDialogInfo.getDialogMessageResId();
            final String message = mSuppliedDialogInfo.getDialogMessage();
            if (messageId != ID_NULL && mSuspendingAppResources != null) {
                try {
                    return mSuspendingAppResources.getString(messageId, suspendedAppLabel);
                } catch (Resources.NotFoundException nfe) {
                    Slog.e(TAG, "Could not resolve string resource id " + messageId);
                }
            } else if (message != null) {
                return String.format(getResources().getConfiguration().getLocales().get(0), message,
                        suspendedAppLabel);
            }
        }
        return getString(R.string.app_suspended_default_message, suspendedAppLabel,
                getAppLabel(suspendingPkg));
    }

    private String resolveNeutralButtonText() {
        final int buttonTextId = (mSuppliedDialogInfo != null)
                ? mSuppliedDialogInfo.getNeutralButtonTextResId() : ID_NULL;
        if (buttonTextId != ID_NULL && mSuspendingAppResources != null) {
            try {
                return mSuspendingAppResources.getString(buttonTextId);
            } catch (Resources.NotFoundException nfe) {
                Slog.e(TAG, "Could not resolve string resource id " + buttonTextId);
            }
        }
        return getString(R.string.app_suspended_more_details);
    }

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        mPm = getPackageManager();
        getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);

        final Intent intent = getIntent();
        mUserId = intent.getIntExtra(Intent.EXTRA_USER_ID, -1);
        if (mUserId < 0) {
            Slog.wtf(TAG, "Invalid user: " + mUserId);
            finish();
            return;
        }
        final String suspendedPackage = intent.getStringExtra(EXTRA_SUSPENDED_PACKAGE);
        final String suspendingPackage = intent.getStringExtra(EXTRA_SUSPENDING_PACKAGE);
        mSuppliedDialogInfo = intent.getParcelableExtra(EXTRA_DIALOG_INFO);
        if (mSuppliedDialogInfo != null) {
            try {
                mSuspendingAppResources = mPm.getResourcesForApplicationAsUser(suspendingPackage,
                        mUserId);
            } catch (PackageManager.NameNotFoundException ne) {
                Slog.e(TAG, "Could not find resources for " + suspendingPackage, ne);
            }
        }

        final AlertController.AlertParams ap = mAlertParams;
        ap.mIcon = resolveIcon();
        ap.mTitle = resolveTitle();
        ap.mMessage = resolveDialogMessage(suspendingPackage, suspendedPackage);
        ap.mPositiveButtonText = getString(android.R.string.ok);
        mMoreDetailsIntent = getMoreDetailsActivity(suspendingPackage, suspendedPackage, mUserId);
        if (mMoreDetailsIntent != null) {
            ap.mNeutralButtonText = resolveNeutralButtonText();
        }
        ap.mPositiveButtonListener = ap.mNeutralButtonListener = this;
        setupAlert();
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        switch (which) {
            case AlertDialog.BUTTON_NEUTRAL:
                startActivityAsUser(mMoreDetailsIntent, UserHandle.of(mUserId));
                Slog.i(TAG, "Started more details activity");
                break;
        }
        finish();
    }

    public static Intent createSuspendedAppInterceptIntent(String suspendedPackage,
            String suspendingPackage, SuspendDialogInfo dialogInfo, int userId) {
        return new Intent()
                .setClassName("android", SuspendedAppActivity.class.getName())
                .putExtra(EXTRA_SUSPENDED_PACKAGE, suspendedPackage)
                .putExtra(EXTRA_DIALOG_INFO, dialogInfo)
                .putExtra(EXTRA_SUSPENDING_PACKAGE, suspendingPackage)
                .putExtra(Intent.EXTRA_USER_ID, userId)
                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
    }
}
