Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fdbef277 authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Initializing LauncherAppState only on the main thread

Bug: 33032833
Change-Id: I7992a5358142dde80aeaf8c6b7a6c7bfef2c8a00
parent 5a2edd65
Loading
Loading
Loading
Loading
+54 −45
Original line number Diff line number Diff line
@@ -16,9 +16,11 @@

package com.android.launcher3;

import android.content.ContentProviderClient;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Looper;
import android.util.Log;

import com.android.launcher3.compat.LauncherAppsCompat;
@@ -26,31 +28,43 @@ import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.dynamicui.ExtractionUtils;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.util.ConfigMonitor;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.TestingUtils;
import com.android.launcher3.util.Thunk;

import java.lang.ref.WeakReference;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;

public class LauncherAppState {

    public static final boolean PROFILE_STARTUP = ProviderConfig.IS_DOGFOOD_BUILD;

    @Thunk final LauncherModel mModel;
    // We do not need any synchronization for this variable as its only written on UI thread.
    private static LauncherAppState INSTANCE;

    private final Context mContext;
    private final LauncherModel mModel;
    private final IconCache mIconCache;
    private final WidgetPreviewLoader mWidgetCache;
    private final InvariantDeviceProfile mInvariantDeviceProfile;

    private static WeakReference<LauncherProvider> sLauncherProvider;
    private static Context sContext;

    private static LauncherAppState INSTANCE;

    private InvariantDeviceProfile mInvariantDeviceProfile;

    public static LauncherAppState getInstance(Context context) {
    public static LauncherAppState getInstance(final Context context) {
        if (INSTANCE == null) {
            INSTANCE = new LauncherAppState();
            if (Looper.myLooper() == Looper.getMainLooper()) {
                INSTANCE = new LauncherAppState(context.getApplicationContext());
            } else {
                try {
                    return new MainThreadExecutor().submit(new Callable<LauncherAppState>() {
                        @Override
                        public LauncherAppState call() throws Exception {
                            return LauncherAppState.getInstance(context);
                        }
                    }).get();
                } catch (InterruptedException|ExecutionException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return INSTANCE;
    }
@@ -60,42 +74,30 @@ public class LauncherAppState {
    }

    public Context getContext() {
        return sContext;
        return mContext;
    }

    static void setLauncherProvider(LauncherProvider provider) {
        if (sLauncherProvider != null) {
            Log.w(Launcher.TAG, "setLauncherProvider called twice! old=" +
                    sLauncherProvider.get() + " new=" + provider);
    private LauncherAppState(Context context) {
        if (getLocalProvider(context) == null) {
            throw new RuntimeException(
                    "Initializing LauncherAppState in the absence of LauncherProvider");
        }
        sLauncherProvider = new WeakReference<>(provider);

        // The content provider exists for the entire duration of the launcher main process and
        // is the first component to get created. Initializing application context here ensures
        // that LauncherAppState always exists in the main process.
        sContext = provider.getContext().getApplicationContext();
        FileLog.setDir(sContext.getFilesDir());
    }

    private LauncherAppState() {
        if (sContext == null) {
            throw new IllegalStateException("LauncherAppState initiated before app context set");
        }

        Log.v(Launcher.TAG, "LauncherAppState initiated");
        Preconditions.assertUIThread();
        mContext = context;

        if (TestingUtils.MEMORY_DUMP_ENABLED) {
            TestingUtils.startTrackingMemory(sContext);
            TestingUtils.startTrackingMemory(mContext);
        }

        mInvariantDeviceProfile = new InvariantDeviceProfile(sContext);
        mIconCache = new IconCache(sContext, mInvariantDeviceProfile);
        mWidgetCache = new WidgetPreviewLoader(sContext, mIconCache);
        mInvariantDeviceProfile = new InvariantDeviceProfile(mContext);
        mIconCache = new IconCache(mContext, mInvariantDeviceProfile);
        mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);

        mModel = new LauncherModel(this, mIconCache,
                Utilities.getOverrideObject(AppFilter.class, sContext, R.string.app_filter_class));
                Utilities.getOverrideObject(AppFilter.class, mContext, R.string.app_filter_class));

        LauncherAppsCompat.getInstance(sContext).addOnAppsChangedCallback(mModel);
        LauncherAppsCompat.getInstance(mContext).addOnAppsChangedCallback(mModel);

        // Register intent receivers
        IntentFilter filter = new IntentFilter();
@@ -112,21 +114,21 @@ public class LauncherAppState {
            filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
        }

        sContext.registerReceiver(mModel, filter);
        UserManagerCompat.getInstance(sContext).enableAndResetCache();
        new ConfigMonitor(sContext).register();
        mContext.registerReceiver(mModel, filter);
        UserManagerCompat.getInstance(mContext).enableAndResetCache();
        new ConfigMonitor(mContext).register();

        ExtractionUtils.startColorExtractionServiceIfNecessary(sContext);
        ExtractionUtils.startColorExtractionServiceIfNecessary(mContext);
    }

    /**
     * Call from Application.onTerminate(), which is not guaranteed to ever be called.
     */
    public void onTerminate() {
        sContext.unregisterReceiver(mModel);
        final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(sContext);
        mContext.unregisterReceiver(mModel);
        final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext);
        launcherApps.removeOnAppsChangedCallback(mModel);
        PackageInstallerCompat.getInstance(sContext).onStop();
        PackageInstallerCompat.getInstance(mContext).onStop();
    }

    /**
@@ -139,7 +141,7 @@ public class LauncherAppState {
    }

    LauncherModel setLauncher(Launcher launcher) {
        sLauncherProvider.get().setLauncherProviderChangeListener(launcher);
        getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
        mModel.initialize(launcher);
        return mModel;
    }
@@ -166,4 +168,11 @@ public class LauncherAppState {
    public static InvariantDeviceProfile getIDP(Context context) {
        return LauncherAppState.getInstance(context).getInvariantDeviceProfile();
    }

    private static LauncherProvider getLocalProvider(Context context) {
        try (ContentProviderClient cl = context.getContentResolver()
                .acquireContentProviderClient(LauncherProvider.AUTHORITY)) {
            return (LauncherProvider) cl.getLocalContentProvider();
        }
    }
}
+5 −1
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.dynamicui.ExtractionUtils;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.provider.LauncherDbUtils;
import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.util.ManagedProfileHeuristic;
@@ -91,7 +92,10 @@ public class LauncherProvider extends ContentProvider {
        }
        mListenerHandler = new Handler(mListenerWrapper);

        LauncherAppState.setLauncherProvider(this);
        // The content provider exists for the entire duration of the launcher main process and
        // is the first component to get created. Initializing FileLog here ensures that it's
        // always available in the main process.
        FileLog.setDir(getContext().getApplicationContext().getFilesDir());
        return true;
    }