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

Commit d38f245a authored by Mohammed Althaf T's avatar Mohammed Althaf T 😊
Browse files

Merge branch '4238-a15-backup' into 'v4.0-a15'

Add backup app support

See merge request e/os/BlissLauncher3!164
parents c9d72b5c bff92aec
Loading
Loading
Loading
Loading
Loading
+56 −6
Original line number Diff line number Diff line
@@ -327,6 +327,17 @@ class WidgetContainer(context: Context, attrs: AttributeSet?) :
                        rebindWidgets()
                    }
                }

                override fun onPackagesAvailable(
                    packageNames: Array<String?>?,
                    user: UserHandle?,
                    replacing: Boolean,
                ) {
                    if (!shouldAttemptWidgetIdRepair(context)) return
                    if (::widgetsDbHelper.isInitialized && ::widgetsAdapter.isInitialized) {
                        rebindWidgets()
                    }
                }
            }

        private var initialWidgetsAdded: Boolean
@@ -422,15 +433,21 @@ class WidgetContainer(context: Context, attrs: AttributeSet?) :
        fun rebindWidgets(backup: Boolean = false) {
            widgetsAdapter.setWidgets(mutableListOf())
            if (!backup) {
                val dbWidgets =
                    widgetsDbHelper.getWidgets().apply {
                        sortedBy { it.position }
                        forEach { addView(it.widgetId) }
                val dbWidgets = widgetsDbHelper.getWidgets().sortedBy { it.position }
                val keepWidgetIds = dbWidgets.mapTo(hashSetOf()) { it.widgetId }
                if (shouldAttemptWidgetIdRepair(context)) {
                    dbWidgets.forEach { restoreWidgetFromDb(it, keepWidgetIds) }
                    if (keepWidgetIds.all { mWidgetManager.getAppWidgetInfo(it) != null }) {
                        LauncherPrefs.get(context)
                            .put(LauncherPrefs.NEEDS_WIDGET_REBIND_AFTER_RESTORE, false)
                    }
                } else {
                    dbWidgets.forEach { widgetInfo -> addView(widgetInfo.widgetId) }
                }

                // Remove all widgets not present in db
                mWidgetHost.appWidgetIds
                    .filter { id -> dbWidgets.all { info -> info.widgetId != id } }
                    .filter { id -> !keepWidgetIds.contains(id) }
                    .forEach { mWidgetHost.deleteAppWidgetId(it) }
            } else {
                if (mOldWidgets.isNotEmpty()) {
@@ -468,8 +485,41 @@ class WidgetContainer(context: Context, attrs: AttributeSet?) :
                    addView(widgetId)
                }
            } else {
                mWidgetHost.deleteAppWidgetId(id)
                mWidgetHost.deleteAppWidgetId(widgetId)
            }
        }

        private fun restoreWidgetFromDb(widgetInfo: WidgetInfo, keepWidgetIds: MutableSet<Int>) {
            if (mWidgetManager.getAppWidgetInfo(widgetInfo.widgetId) != null) {
                addView(widgetInfo.widgetId)
                return
            }

            // Seedvault/app-data restore can bring back our widget database, but appWidgetIds are
            // allocated and persisted by the system; they often don't survive restores.
            val newWidgetId = mWidgetHost.allocateAppWidgetId()
            val isWidgetBound =
                mWidgetManager.bindAppWidgetIdIfAllowed(newWidgetId, widgetInfo.component)
            if (!isWidgetBound) {
                mWidgetHost.deleteAppWidgetId(newWidgetId)
                Logger.e(
                    TAG,
                    "Could not rebind restored widget ${widgetInfo.component.flattenToString()} (oldId=${widgetInfo.widgetId})",
                )
                return
            }

            if (newWidgetId != widgetInfo.widgetId) {
                widgetsDbHelper.updateWidgetId(widgetInfo.widgetId, newWidgetId)
                keepWidgetIds.remove(widgetInfo.widgetId)
                keepWidgetIds.add(newWidgetId)
                mWidgetHost.deleteAppWidgetId(widgetInfo.widgetId)
            }
            addView(newWidgetId)
        }

        private fun shouldAttemptWidgetIdRepair(context: Context): Boolean {
            return LauncherPrefs.get(context).get(LauncherPrefs.NEEDS_WIDGET_REBIND_AFTER_RESTORE)
        }

        private fun addView(widgetId: Int, backup: Boolean = false) {
+21 −0
Original line number Diff line number Diff line
@@ -94,6 +94,27 @@ class WidgetsDbHelper(context: Context) :
        }
    }

    fun updateWidgetId(oldId: Int, newId: Int) {
        if (oldId == newId) {
            return
        }
        Logger.d(TAG, "Updating widgetId $oldId -> $newId")
        writableDatabase.use { db ->
            db.beginTransaction()
            try {
                // Avoid primary-key conflicts if the new id already exists for some reason.
                db.execSQL("DELETE FROM $WIDGETS_TABLE WHERE widgetId = ?", arrayOf(newId))
                db.execSQL(
                    "UPDATE $WIDGETS_TABLE SET widgetId = ? WHERE widgetId = ?",
                    arrayOf(newId, oldId),
                )
                db.setTransactionSuccessful()
            } finally {
                db.endTransaction()
            }
        }
    }

    fun updateHeight(id: Int, height: Int) {
        Logger.d(TAG, "Updating widget $id height to $height")
        writableDatabase.use { db ->
+7 −5
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content xmlns:android="http://schemas.android.com/apk/res/android">
<full-backup-content>

    <!-- 1.9.0 Database -->
    <include domain="database" path="launcher_db" />

    <!-- QSB Widgets Database -->
    <include domain="database" path="qsb_widgets.db" />
    <include domain="database" path="qsb_widgets" />

    <include domain="database" path="app_icons.db" />
    <include domain="database" path="launcher.db" />
    <include domain="database" path="launcher_5_by_8.db" />
    <include domain="database" path="launcher_5_by_7.db" />
    <include domain="database" path="launcher_6_by_6.db" />
    <include domain="database" path="launcher_6_by_5.db" />
    <include domain="database" path="launcher_5_by_6.db" />
    <include domain="database" path="launcher_4_by_6.db" />
    <include domain="database" path="launcher_4_by_5.db" />
    <include domain="database" path="launcher_4_by_6.db" />
    <include domain="database" path="launcher_4_by_4.db" />
    <include domain="database" path="launcher_3_by_3.db" />
    <include domain="database" path="launcher_2_by_2.db" />
    <include domain="database" path="launcher_7_by_3.db" />
    <include domain="database" path="launcher_8_by_3.db" />
    <include domain="sharedpref" path="com.android.launcher3.device.prefs.xml" />
    <include domain="sharedpref" path="com.android.launcher3.prefs.xml" />
    <include domain="sharedpref" path="plugin_prefs.xml" />
    <include domain="file" path="downgrade_schema.json" />

</full-backup-content>
 No newline at end of file
+25 −0
Original line number Diff line number Diff line
@@ -40,7 +40,9 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ArchiveCompatibilityParams;
import android.net.Uri;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;

import androidx.annotation.Nullable;
@@ -53,6 +55,7 @@ import com.android.launcher3.icons.LauncherIconProvider;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.lineage.trust.HiddenAppsFilter;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.CompactWorkspaceAfterRestoreTask;
import com.android.launcher3.model.ModelLauncherCallbacks;
import com.android.launcher3.model.WidgetsFilterDataProvider;
import com.android.launcher3.notification.NotificationListener;
@@ -200,6 +203,7 @@ public class LauncherAppState implements SafeCloseable {
        mAppMonitor.onAppCreated(mContext);
        // Register an observer to notify Launcher about Private Space settings toggle.
        registerPrivateSpaceHideWhenLockListener(settingsCache);
        registerSetupCompleteListener(settingsCache);
    }

    public LauncherAppState(Context context, @Nullable String iconCacheFileName) {
@@ -225,6 +229,27 @@ public class LauncherAppState implements SafeCloseable {
        }
    }

    private void registerSetupCompleteListener(SettingsCache settingsCache) {
        // After restore, compact the workspace only once SUW is complete.
        Uri setupCompleteUri =
                Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE);
        SettingsCache.OnChangeListener setupCompleteListener =
                isSetupComplete -> {
                    if (!isSetupComplete || !LauncherPrefs.get(mContext).get(
                            LauncherPrefs.NEEDS_WORKSPACE_REORDER_AFTER_RESTORE)) {
                        return;
                    }
                    mModel.enqueueModelUpdateTask(new CompactWorkspaceAfterRestoreTask());
                };

        settingsCache.register(setupCompleteUri, setupCompleteListener);
        setupCompleteListener.onSettingsChanged(
                settingsCache.getValue(setupCompleteUri, 0));

        mOnTerminateCallback.add(() -> settingsCache.unregister(setupCompleteUri,
                setupCompleteListener));
    }

    private void registerPrivateSpaceHideWhenLockListener(SettingsCache settingsCache) {
        SettingsCache.OnChangeListener psHideWhenLockChangedListener =
                this::onPrivateSpaceHideWhenLockChanged;
+4 −0
Original line number Diff line number Diff line
package com.android.launcher3;

import static com.android.launcher3.LauncherPrefs.NEEDS_WIDGET_REBIND_AFTER_RESTORE;
import static com.android.launcher3.LauncherPrefs.NEEDS_WORKSPACE_REORDER_AFTER_RESTORE;
import static com.android.launcher3.LauncherPrefs.NO_DB_FILES_RESTORED;

import android.app.backup.BackupAgent;
@@ -54,6 +56,8 @@ public class LauncherBackupAgent extends BackupAgent {
    public void onRestoreFinished() {
        RestoreDbTask.setPending(this);
        FileLog.d(TAG, "onRestoreFinished: set pending for RestoreDbTask");
        LauncherPrefs.get(this).putSync(NEEDS_WIDGET_REBIND_AFTER_RESTORE.to(true));
        LauncherPrefs.get(this).putSync(NEEDS_WORKSPACE_REORDER_AFTER_RESTORE.to(true));
        markIfFilesWereNotActuallyRestored();
    }

Loading