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

Commit 3e650c37 authored by Chaohui Wang's avatar Chaohui Wang Committed by Android (Google) Code Review
Browse files

Merge "Refactor PrintSettings (1/n)" into main

parents b96feafd 3362e5d1
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -7,3 +7,13 @@ flag {
    description: "Change to the new APN page."
    bug: "298906796"
}

flag {
    name: "refactor_print_settings"
    namespace: "settings_experience"
    description: "Refactor the PrintSettings page."
    bug: "320076351"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
+76 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.settings.print

import android.content.Context
import android.graphics.drawable.Drawable
import android.print.PrintManager
import android.printservice.PrintServiceInfo
import com.android.settings.R
import com.android.settingslib.spa.framework.util.mapItem
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map

class PrintRepository(private val context: Context) {

    private val printManager = context.getSystemService(PrintManager::class.java)!!
    private val packageManager = context.packageManager

    data class PrintServiceDisplayInfo(
        val title: String,
        val isEnabled: Boolean,
        val summary: String,
        val icon: Drawable,
        val componentName: String,
    )

    fun printServiceDisplayInfosFlow(): Flow<List<PrintServiceDisplayInfo>> =
        printServicesFlow()
            .mapItem { printService -> printService.toPrintServiceDisplayInfo() }
            .conflate()
            .flowOn(Dispatchers.Default)

    private fun PrintServiceInfo.toPrintServiceDisplayInfo() = PrintServiceDisplayInfo(
        title = resolveInfo.loadLabel(packageManager).toString(),
        isEnabled = isEnabled,
        summary = context.getString(
            if (isEnabled) R.string.print_feature_state_on else R.string.print_feature_state_off
        ),
        icon = resolveInfo.loadIcon(packageManager),
        componentName = componentName.flattenToString(),
    )

    private fun printServicesFlow(): Flow<List<PrintServiceInfo>> =
        printManager.printServicesChangeFlow()
            .map { printManager.getPrintServices(PrintManager.ALL_SERVICES) }
            .conflate()
            .flowOn(Dispatchers.Default)

    private companion object {
        fun PrintManager.printServicesChangeFlow(): Flow<Unit> = callbackFlow {
            val listener = PrintManager.PrintServicesChangeListener { trySend(Unit) }
            addPrintServicesChangeListener(listener, null)
            trySend(Unit)
            awaitClose { removePrintServicesChangeListener(listener) }
        }.conflate().flowOn(Dispatchers.Default)
    }
}
+12 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.loader.app.LoaderManager.LoaderCallbacks;
import androidx.loader.content.AsyncTaskLoader;
@@ -54,7 +55,9 @@ import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;

import com.android.settings.R;
import com.android.settings.flags.Flags;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.spa.SpaActivity;
import com.android.settingslib.search.Indexable;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.widget.AppPreference;
@@ -101,6 +104,15 @@ public class PrintSettingsFragment extends ProfileSettingsPreferenceFragment
        super(UserManager.DISALLOW_PRINTING);
    }

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        if (Flags.refactorPrintSettings()) {
            SpaActivity.startSpaActivity(context, PrintSettingsPageProvider.INSTANCE.getName());
            finish();
        }
    }

    @Override
    protected String getLogTag() {
        return TAG;
+102 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.settings.print

import android.app.settings.SettingsEnums
import android.os.Bundle
import androidx.annotation.VisibleForTesting
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.core.os.bundleOf
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settings.R
import com.android.settings.core.SubSettingLauncher
import com.android.settings.print.PrintRepository.PrintServiceDisplayInfo
import com.android.settings.print.PrintSettingsFragment.EXTRA_CHECKED
import com.android.settings.print.PrintSettingsFragment.EXTRA_SERVICE_COMPONENT_NAME
import com.android.settings.print.PrintSettingsFragment.EXTRA_TITLE
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.compose.rememberDrawablePainter
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
import com.android.settingslib.spa.widget.ui.Category
import com.android.settingslib.spaprivileged.template.common.UserProfilePager

object PrintSettingsPageProvider : SettingsPageProvider {
    override val name = "PrintSettings"

    @Composable
    override fun Page(arguments: Bundle?) {
        RegularScaffold(title = stringResource(R.string.print_settings)) {
            val context = LocalContext.current
            val printRepository = remember(context) { PrintRepository(context) }
            UserProfilePager {
                PrintServices(printRepository)
            }
        }
    }

    @Composable
    private fun PrintServices(printRepository: PrintRepository) {
        val printServiceDisplayInfos by remember {
            printRepository.printServiceDisplayInfosFlow()
        }.collectAsStateWithLifecycle(initialValue = emptyList())
        Category(title = stringResource(R.string.print_settings_title)) {
            for (printServiceDisplayInfo in printServiceDisplayInfos) {
                PrintService(printServiceDisplayInfo)
            }
        }
    }

    @VisibleForTesting
    @Composable
    fun PrintService(displayInfo: PrintServiceDisplayInfo) {
        val context = LocalContext.current
        Preference(model = object : PreferenceModel {
            override val title = displayInfo.title
            override val summary = { displayInfo.summary }
            override val icon: @Composable () -> Unit = {
                Image(
                    painter = rememberDrawablePainter(displayInfo.icon),
                    contentDescription = null,
                    modifier = Modifier.size(SettingsDimension.appIconItemSize),
                )
            }
            override val onClick = {
                SubSettingLauncher(context).apply {
                    setDestination(PrintServiceSettingsFragment::class.qualifiedName)
                    setArguments(
                        bundleOf(
                            EXTRA_CHECKED to displayInfo.isEnabled,
                            EXTRA_TITLE to displayInfo.title,
                            EXTRA_SERVICE_COMPONENT_NAME to displayInfo.componentName
                        )
                    )
                    setSourceMetricsCategory(SettingsEnums.PRINT_SETTINGS)
                }.launch()
            }
        })
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.settings.spa
import android.content.Context
import android.util.FeatureFlagUtils
import com.android.settings.network.apn.ApnEditPageProvider
import com.android.settings.print.PrintSettingsPageProvider
import com.android.settings.spa.about.AboutPhonePageProvider
import com.android.settings.spa.app.AllAppListPageProvider
import com.android.settings.spa.app.AppsMainPageProvider
@@ -120,6 +121,7 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) {
        BatteryOptimizationModeAppListPageProvider,
        NetworkCellularGroupProvider(),
        WifiPrivacyPageProvider,
        PrintSettingsPageProvider,
    )

    override val logger = if (FeatureFlagUtils.isEnabled(
Loading