/*
 * Copyright (C) 2019 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.documentsui.theme;

import android.content.Context;
import android.content.om.OverlayInfo;
import android.content.om.OverlayManager;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.UserHandle;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.util.Consumer;

import java.util.List;

/**
 * ThemeOverlayManager manage runtime resource overlay packages of DocumentsUI
 */
public class ThemeOverlayManager {
    private static final String TAG = ThemeOverlayManager.class.getSimpleName();
    private static final String PERMISSION_CHANGE_OVERLAY_PACKAGES =
            "android.permission.CHANGE_OVERLAY_PACKAGES";

    private final OverlayManager mOverlayManager;
    private String mTargetPackageId;
    private UserHandle mUserHandle;

    public ThemeOverlayManager(@NonNull OverlayManager overlayManager, String targetPackageId) {
        mOverlayManager = overlayManager;
        mTargetPackageId = targetPackageId;
        mUserHandle = UserHandle.of(UserHandle.myUserId());
    }

    /**
     * Apply runtime overlay package, dynamic enabled overlay do not support priority yet
     *
     * @param context the activity or context from caller
     * @param enabled whether or not enable overlay package
     */
    public void applyOverlays(Context context, boolean enabled, Consumer<Boolean> callback) {
        if (ContextCompat.checkSelfPermission(context, PERMISSION_CHANGE_OVERLAY_PACKAGES)
                == PackageManager.PERMISSION_GRANTED) {
            setEnabled(enabled, callback);
        } else {
            Log.w(TAG, "Permission: " + PERMISSION_CHANGE_OVERLAY_PACKAGES + " did not granted!");
            callback.accept(false);
        }
    }

    private List<OverlayInfo> getOverlayInfo() {
        // (b/132933212): Only static overlay package support priority attrs
        // TODO: Alternative way to support enabled multiple overlay packages by priority is
        //       tag meta-data in the application of overlay package's AndroidManifest.xml
        // TODO: Parse meta data through PM in DocumentsApplication and use collection to reorder
        return mOverlayManager.getOverlayInfosForTarget(mTargetPackageId, mUserHandle);
    }

    /**
     * Return the OverlayInfo which is provided by the docsUI overlay package pre-installed in
     * device. We assume there should only one docsUI overlay package because priority not work
     * for non-static overlay, so vendor should put only one docsUI overlay package.
     *
     * @param pm the PackageManager
     */
    @Nullable
    public OverlayInfo getValidOverlay(@NonNull PackageManager pm) {
        for (OverlayInfo info : getOverlayInfo()) {
            try {
                final ApplicationInfo ai = pm.getApplicationInfo(info.getPackageName(), 0);
                if ((ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                    return info;
                }
            } catch (PackageManager.NameNotFoundException e) {
                Log.w(TAG, "Can't get ApplicationInfo of overlay package " + info.getPackageName());
            }
        }
        return null;
    }

    private void setEnabled(boolean enabled, Consumer<Boolean> callback) {
        new AsyncTask<Void, Void, Boolean>() {
            @Override
            protected Boolean doInBackground(Void... params) {
                return setEnabledOverlayPackages(getOverlayInfo(), enabled);
            }

            @Override
            protected void onPostExecute(Boolean result) {
                super.onPostExecute(result);
                if (callback != null) {
                    callback.accept(result);
                }
            }
        }.execute();
    }

    private boolean setEnabledOverlayPackages(List<OverlayInfo> infos, boolean enabled) {
        boolean bSuccess = true;
        for (OverlayInfo info : infos) {
            try {
                if (info.isEnabled() != enabled) {
                    mOverlayManager.setEnabled(info.getPackageName(), enabled, mUserHandle);
                } else {
                    Log.w(TAG, "Skip enabled overlay package:" + info.getPackageName()
                            + ", user:" + mUserHandle);
                    bSuccess = false;
                }
            } catch (RuntimeException re) {
                Log.e(TAG, "Failed to enable overlay: " + info.getPackageName() + ", user: "
                        + mUserHandle);
                bSuccess = false;
            }
        }
        return bSuccess;
    }
}
