/*
 * 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.launcher3.icons;

import static android.content.Intent.ACTION_MANAGED_PROFILE_ADDED;
import static android.content.Intent.ACTION_MANAGED_PROFILE_REMOVED;

import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.SparseLongArray;

import androidx.annotation.NonNull;

import com.android.launcher3.icons.cache.BaseIconCache;

/**
 * Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class
 * that are threadsafe.
 */
@TargetApi(Build.VERSION_CODES.P)
public class SimpleIconCache extends BaseIconCache {

    private static SimpleIconCache sIconCache = null;
    private static final Object CACHE_LOCK = new Object();

    private final SparseLongArray mUserSerialMap = new SparseLongArray(2);
    private final UserManager mUserManager;

    public SimpleIconCache(Context context, String dbFileName, Looper bgLooper, int iconDpi,
            int iconPixelSize, boolean inMemoryCache) {
        super(context, dbFileName, bgLooper, iconDpi, iconPixelSize, inMemoryCache);
        mUserManager = context.getSystemService(UserManager.class);

        // Listen for user cache changes.
        IntentFilter filter = new IntentFilter(ACTION_MANAGED_PROFILE_ADDED);
        filter.addAction(ACTION_MANAGED_PROFILE_REMOVED);
        context.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                resetUserCache();
            }
        }, filter, null, new Handler(bgLooper), 0);
    }

    @Override
    public long getSerialNumberForUser(@NonNull UserHandle user) {
        synchronized (mUserSerialMap) {
            int index = mUserSerialMap.indexOfKey(user.getIdentifier());
            if (index >= 0) {
                return mUserSerialMap.valueAt(index);
            }
            long serial = mUserManager.getSerialNumberForUser(user);
            mUserSerialMap.put(user.getIdentifier(), serial);
            return serial;
        }
    }

    private void resetUserCache() {
        synchronized (mUserSerialMap) {
            mUserSerialMap.clear();
        }
    }

    @Override
    protected boolean isInstantApp(@NonNull ApplicationInfo info) {
        return info.isInstantApp();
    }

    @NonNull
    @Override
    public BaseIconFactory getIconFactory() {
        return IconFactory.obtain(context);
    }

    public static SimpleIconCache getIconCache(Context context) {
        synchronized (CACHE_LOCK) {
            if (sIconCache != null) {
                return sIconCache;
            }
            boolean inMemoryCache =
                    context.getResources().getBoolean(R.bool.simple_cache_enable_im_memory);
            String dbFileName = context.getString(R.string.cache_db_name);

            HandlerThread bgThread = new HandlerThread("simple-icon-cache");
            bgThread.start();

            sIconCache = new SimpleIconCache(context.getApplicationContext(), dbFileName,
                    bgThread.getLooper(), context.getResources().getConfiguration().densityDpi,
                    context.getResources().getDimensionPixelSize(R.dimen.default_icon_bitmap_size),
                    inMemoryCache);
            return sIconCache;
        }
    }
}
