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

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

Adding helper methods to caching DB

Bug: 420997234
Test: Updated tests
Flag: EXEMPT refactor
Change-Id: Ia443aa8498eceea94269a5422e7cc7a8bc39c9e8
parent e32dcb7a
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.launcher3.icons
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat.PNG
import android.graphics.BitmapFactory
import android.graphics.BitmapFactory.Options
import android.graphics.BlendMode
import android.graphics.BlendModeColorFilter
import android.graphics.Canvas
@@ -35,7 +37,6 @@ import android.graphics.RegionIterator
import android.util.Log
import androidx.annotation.ColorInt
import androidx.core.graphics.ColorUtils.compositeColors
import com.android.launcher3.icons.GraphicsUtils.resize
import com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR
import com.android.launcher3.icons.ShadowGenerator.BLUR_FACTOR
import java.io.ByteArrayOutputStream
@@ -73,6 +74,20 @@ object GraphicsUtils {
        }
    }

    /** Tries to decode the [ByteArray] into a [Bitmap] consuming any parsing errors */
    fun ByteArray.parseBitmapSafe(config: Bitmap.Config): Bitmap? =
        try {
            BitmapFactory.decodeByteArray(
                /* data= */ this,
                /* offset= */ 0,
                /* length= */ size,
                Options().apply { inPreferredConfig = config },
            )
        } catch (e: Exception) {
            Log.e(TAG, "Error parsing persisted bitmap", e)
            null
        }

    /**
     * Try go guesstimate how much space the icon will take when serialized to avoid unnecessary
     * allocations/copies during the write (4 bytes per pixel).
+1 −1
Original line number Diff line number Diff line
@@ -55,7 +55,7 @@ interface IconThemeController {
    ): ThemedBitmap

    fun decode(
        data: ByteArray,
        bytes: ByteArray,
        info: BitmapInfo,
        factory: BaseIconFactory,
        sourceHint: SourceHint,
+26 −39
Original line number Diff line number Diff line
@@ -24,8 +24,6 @@ import android.content.pm.LauncherApps
import android.content.pm.PackageManager
import android.content.pm.PackageManager.NameNotFoundException
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteException
import android.database.sqlite.SQLiteReadOnlyDatabaseException
import android.graphics.Bitmap
import android.graphics.Bitmap.Config.HARDWARE
@@ -93,7 +91,7 @@ constructor(

    @JvmField val workerHandler = Handler(bgLooper)

    @JvmField protected var iconDb = IconDB(context, dbFileName, iconPixelSize)
    @JvmField protected var iconDb = createIconDb(iconPixelSize)

    private var defaultIcon: BitmapInfo? = null
    private val userFlagOpMap = SparseArray<FlagOp>()
@@ -133,7 +131,7 @@ constructor(
            userFlagOpMap.clear()
            iconDb.clear()
            iconDb.close()
            iconDb = IconDB(context, dbFileName, iconPixelSize)
            iconDb = createIconDb(iconPixelSize)
            cache.clear()
        } catch (e: SQLiteReadOnlyDatabaseException) {
            // This is known to happen during repeated backup and restores, if the Launcher is in
@@ -486,28 +484,22 @@ constructor(
        lookupFlags: CacheLookupFlag,
        cachingLogic: CachingLogic<*>,
    ): Boolean {
        var c: Cursor? = null
        Trace.beginSection("loadIconIndividually")
        try {
            c =
                iconDb.query(
            return iconDb.querySingleEntry(
                lookupFlags.toLookupColumns(),
                "$COLUMN_COMPONENT = ? AND $COLUMN_USER = ?",
                arrayOf(
                    cacheKey.componentName.flattenToString(),
                    getSerialNumberForUser(cacheKey.user).toString(),
                ),
                )
            if (c.moveToNext()) {
                return updateTitleAndIconLocked(cacheKey, entry, c, lookupFlags, cachingLogic)
                false,
            ) {
                updateTitleAndIconLocked(cacheKey, entry, it, lookupFlags, cachingLogic)
            }
        } catch (e: SQLiteException) {
            Log.d(TAG, "Error reading icon cache", e)
        } finally {
            c?.close()
            Trace.endSection()
        }
        return false
    }

    private fun updateTitleAndIconLocked(
@@ -561,7 +553,7 @@ constructor(
                    if (themeController != null && monoIconData != null) {
                        entry.bitmap.themedBitmap =
                            themeController.decode(
                                data = monoIconData,
                                bytes = monoIconData,
                                info = entry.bitmap,
                                factory = factory,
                                sourceHint =
@@ -614,18 +606,15 @@ constructor(
        Log.d(TAG, message, e)
    }

    /** Cache class to store the actual entries on disk */
    class IconDB(context: Context, dbFileName: String?, iconPixelSize: Int) :
    /** Creates a cache class to store the actual entries on disk */
    private fun createIconDb(iconPixelSize: Int) =
        SQLiteCacheHelper(
            context,
            dbFileName,
            (RELEASE_VERSION shl 16) + iconPixelSize,
            TABLE_NAME,
        ) {

        override fun onCreateTable(db: SQLiteDatabase) {
            db.execSQL(
                ("CREATE TABLE IF NOT EXISTS $TABLE_NAME (" +
            "CREATE TABLE IF NOT EXISTS $TABLE_NAME (" +
                "$COLUMN_COMPONENT TEXT NOT NULL, " +
                "$COLUMN_USER INTEGER NOT NULL, " +
                "$COLUMN_FRESHNESS_ID TEXT, " +
@@ -635,9 +624,7 @@ constructor(
                "$COLUMN_FLAGS INTEGER NOT NULL DEFAULT 0, " +
                "$COLUMN_LABEL TEXT, " +
                "PRIMARY KEY ($COLUMN_COMPONENT, $COLUMN_USER) " +
                    ");")
            )
        }
                ");"
        }

    companion object {
+3 −3
Original line number Diff line number Diff line
@@ -111,16 +111,16 @@ class MonoIconThemeController(
    }

    override fun decode(
        data: ByteArray,
        bytes: ByteArray,
        info: BitmapInfo,
        factory: BaseIconFactory,
        sourceHint: SourceHint,
    ): ThemedBitmap {
        val icon = info.icon
        if (data.size != icon.height * icon.width) return ThemedBitmap.NOT_SUPPORTED
        if (bytes.size != icon.height * icon.width) return ThemedBitmap.NOT_SUPPORTED

        var monoBitmap = Bitmap.createBitmap(icon.width, icon.height, ALPHA_8)
        monoBitmap.copyPixelsFromBuffer(ByteBuffer.wrap(data))
        monoBitmap.copyPixelsFromBuffer(ByteBuffer.wrap(bytes))

        val hwMonoBitmap = monoBitmap.copy(HARDWARE, false /*isMutable*/)
        if (hwMonoBitmap != null) {
+0 −58
Original line number Diff line number Diff line
/*
 * 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.util;

import static android.database.sqlite.SQLiteDatabase.NO_LOCALIZED_COLLATORS;

import android.content.Context;
import android.content.ContextWrapper;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteDatabase.OpenParams;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Build;

/**
 * Extension of {@link SQLiteOpenHelper} which avoids creating default locale table by
 * A context wrapper which creates databases without support for localized collators.
 */
public abstract class NoLocaleSQLiteHelper extends SQLiteOpenHelper {

    private static final boolean ATLEAST_P =
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;

    public NoLocaleSQLiteHelper(Context context, String name, int version) {
        super(ATLEAST_P ? context : new NoLocalContext(context), name, null, version);
        if (ATLEAST_P) {
            setOpenParams(new OpenParams.Builder().addOpenFlags(NO_LOCALIZED_COLLATORS).build());
        }
    }

    private static class NoLocalContext extends ContextWrapper {
        public NoLocalContext(Context base) {
            super(base);
        }

        @Override
        public SQLiteDatabase openOrCreateDatabase(
                String name, int mode, CursorFactory factory, DatabaseErrorHandler errorHandler) {
            return super.openOrCreateDatabase(
                    name, mode | Context.MODE_NO_LOCALIZED_COLLATORS, factory, errorHandler);
        }
    }
}
Loading