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

Commit 1510991e authored by Zekan Qian's avatar Zekan Qian
Browse files

Support slice in Spa.

Add slice API.
Add demo provider & demo presenter.
Add AllSlice page in Debug Activity.
Build end-to-end workflow to support Slice.

Bug: 244122804
Test: unit-test & local build gallery
Change-Id: I185f1442882cf0ed168b1fbf8e68bc70905aa8c4
parent bb926946
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -24,6 +24,9 @@ android_library {
    srcs: ["src/**/*.kt"],

    static_libs: [
        "androidx.slice_slice-builders",
        "androidx.slice_slice-core",
        "androidx.slice_slice-view",
        "androidx.compose.material3_material3",
        "androidx.compose.material_material-icons-extended",
        "androidx.compose.runtime_runtime",
+3 −0
Original line number Diff line number Diff line
@@ -55,6 +55,9 @@ android {

dependencies {
    api "androidx.appcompat:appcompat:1.7.0-alpha01"
    api "androidx.slice:slice-builders:1.1.0-alpha02"
    api "androidx.slice:slice-core:1.1.0-alpha02"
    api "androidx.slice:slice-view:1.1.0-alpha02"
    api "androidx.compose.material3:material3:1.1.0-alpha01"
    api "androidx.compose.material:material-icons-extended:$jetpack_compose_version"
    api "androidx.compose.runtime:runtime-livedata:$jetpack_compose_version"
+2 −2
Original line number Diff line number Diff line
@@ -119,7 +119,7 @@ class SpaSearchProvider : ContentProvider() {
        val entryRepository by spaEnvironment.entryRepository
        val cursor = MatrixCursor(QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY.getColumns())
        for (entry in entryRepository.getAllEntries()) {
            if (!entry.isAllowSearch || entry.mutableStatus) continue
            if (!entry.isAllowSearch || entry.hasMutableStatus) continue
            fetchStatusData(entry, cursor)
        }
        return cursor
@@ -129,7 +129,7 @@ class SpaSearchProvider : ContentProvider() {
        val entryRepository by spaEnvironment.entryRepository
        val cursor = MatrixCursor(QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY.getColumns())
        for (entry in entryRepository.getAllEntries()) {
            if (!entry.isAllowSearch || !entry.mutableStatus) continue
            if (!entry.isAllowSearch || !entry.hasMutableStatus) continue
            fetchStatusData(entry, cursor)
        }
        return cursor
+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.settingslib.spa.framework

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory

class SpaSliceBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        val sliceRepository = SpaEnvironmentFactory.instance.sliceDataRepository
        val sliceUri = intent?.data ?: return
        val sliceData = sliceRepository.getActiveSliceData(sliceUri) ?: return
        sliceData.doAction()
    }
}
+76 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.settingslib.spa.framework

import android.net.Uri
import android.util.Log
import androidx.lifecycle.Observer
import androidx.slice.Slice
import androidx.slice.SliceProvider
import com.android.settingslib.spa.framework.common.EntrySliceData
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext

private const val TAG = "SpaSliceProvider"

class SpaSliceProvider : SliceProvider(), Observer<Slice?> {
    private fun getOrPutSliceData(sliceUri: Uri): EntrySliceData? {
        if (!SpaEnvironmentFactory.isReady()) return null
        return SpaEnvironmentFactory.instance.sliceDataRepository.getOrBuildSliceData(sliceUri)
    }

    override fun onBindSlice(sliceUri: Uri): Slice? {
        if (context == null) return null
        Log.d(TAG, "onBindSlice: $sliceUri")
        return getOrPutSliceData(sliceUri)?.value
    }

    override fun onSlicePinned(sliceUri: Uri) {
        Log.d(TAG, "onSlicePinned: $sliceUri")
        super.onSlicePinned(sliceUri)
        val sliceLiveData = getOrPutSliceData(sliceUri) ?: return
        runBlocking {
            withContext(Dispatchers.Main) {
                sliceLiveData.observeForever(this@SpaSliceProvider)
            }
        }
    }

    override fun onSliceUnpinned(sliceUri: Uri) {
        Log.d(TAG, "onSliceUnpinned: $sliceUri")
        super.onSliceUnpinned(sliceUri)
        val sliceLiveData = getOrPutSliceData(sliceUri) ?: return
        runBlocking {
            withContext(Dispatchers.Main) {
                sliceLiveData.removeObserver(this@SpaSliceProvider)
            }
        }
    }

    override fun onChanged(slice: Slice?) {
        val uri = slice?.uri ?: return
        Log.d(TAG, "onChanged: $uri")
        context?.contentResolver?.notifyChange(uri, null)
    }

    override fun onCreateSliceProvider(): Boolean {
        Log.d(TAG, "onCreateSliceProvider")
        return true
    }
}
 No newline at end of file
Loading