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

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

Merge changes from topics "AlarmsAndRemindersAppList", "TogglePermissionAppInfoPage-entry"

* changes:
  Add new Alarms & reminders App List
  Add AppSettings page
parents 9ee4834a d4f1898e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -283,7 +283,7 @@ public class ManageApplications extends InstrumentedFragment
        final String className = getClassName(activity.getIntent(), getArguments());
        if (className.equals(ManageExternalSourcesActivity.class.getName())) {
            SpaActivity.startSpaActivity(
                    context, InstallUnknownAppsListProvider.INSTANCE.getRoute());
                    context, InstallUnknownAppsListProvider.INSTANCE.getAppListRoute());
            activity.finish();
        }
    }
+5 −1
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.settings.spa

import com.android.settings.spa.app.AppsMainPageProvider
import com.android.settings.spa.app.appsettings.AppSettingsProvider
import com.android.settings.spa.app.specialaccess.AlarmsAndRemindersAppListProvider
import com.android.settings.spa.app.specialaccess.AllFilesAccessAppListProvider
import com.android.settings.spa.app.specialaccess.DisplayOverOtherAppsAppListProvider
import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider
@@ -42,14 +44,16 @@ object SpaEnvironment {
                DisplayOverOtherAppsAppListProvider,
                MediaManagementAppsAppListProvider,
                ModifySystemSettingsAppListProvider,
                InstallUnknownAppsListProvider,
                PictureInPictureListProvider,
                InstallUnknownAppsListProvider,
                AlarmsAndRemindersAppListProvider,
            ),
        )
        SettingsPageProviderRepository(
            allPageProviders = listOf(
                HomePageProvider,
                AppsMainPageProvider,
                AppSettingsProvider,
                SpecialAppAccessPageProvider,
                NotificationMainPageProvider,
                AppListNotificationsPageProvider,
+85 −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.settings.spa.app.appsettings

import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.os.Bundle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.res.stringResource
import androidx.navigation.NavType
import androidx.navigation.navArgument
import com.android.settings.R
import com.android.settings.spa.app.specialaccess.AlarmsAndRemindersAppListProvider
import com.android.settings.spa.app.specialaccess.DisplayOverOtherAppsAppListProvider
import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider
import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider
import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
import com.android.settingslib.spa.widget.ui.Category
import com.android.settingslib.spaprivileged.model.app.PackageManagers
import com.android.settingslib.spaprivileged.model.app.toRoute
import com.android.settingslib.spaprivileged.template.app.AppInfoProvider

private const val PACKAGE_NAME = "packageName"
private const val USER_ID = "userId"

object AppSettingsProvider : SettingsPageProvider {
    override val name = "AppSettings"

    override val parameter = listOf(
        navArgument(PACKAGE_NAME) { type = NavType.StringType },
        navArgument(USER_ID) { type = NavType.IntType },
    )

    @Composable
    override fun Page(arguments: Bundle?) {
        val packageName = arguments!!.getString(PACKAGE_NAME)!!
        val userId = arguments.getInt(USER_ID)
        remember { PackageManagers.getPackageInfoAsUser(packageName, userId) }?.let {
            AppSettings(it)
        }
    }

    @Composable
    fun navigator(app: ApplicationInfo) = navigator(route = "$name/${app.toRoute()}")
}

@Composable
private fun AppSettings(packageInfo: PackageInfo) {
    RegularScaffold(title = stringResource(R.string.application_info_label)) {
        val appInfoProvider = remember { AppInfoProvider(packageInfo) }

        appInfoProvider.AppInfo()

        Category(title = stringResource(R.string.advanced_apps)) {
            val app = packageInfo.applicationInfo
            DisplayOverOtherAppsAppListProvider.InfoPageEntryItem(app)
            ModifySystemSettingsAppListProvider.InfoPageEntryItem(app)
            PictureInPictureListProvider.InfoPageEntryItem(app)
            InstallUnknownAppsListProvider.InfoPageEntryItem(app)
            // TODO: interact_across_profiles
            AlarmsAndRemindersAppListProvider.InfoPageEntryItem(app)
        }

        // TODO: app_installer
        appInfoProvider.FooterAppVersion()
    }
}
+99 −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.settings.spa.app.specialaccess

import android.Manifest
import android.app.AlarmManager
import android.app.compat.CompatChanges
import android.content.Context
import android.content.pm.ApplicationInfo
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import com.android.settings.R
import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.model.app.PackageManagers
import com.android.settingslib.spaprivileged.model.app.PackageManagers.hasRequestPermission
import com.android.settingslib.spaprivileged.model.app.userHandle
import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListModel
import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map

object AlarmsAndRemindersAppListProvider : TogglePermissionAppListProvider {
    override val permissionType = "AlarmsAndReminders"
    override fun createModel(context: Context) = AlarmsAndRemindersAppListModel(context)
}

data class AlarmsAndRemindersAppRecord(
    override val app: ApplicationInfo,
    val isChangeable: Boolean,
    var controller: AlarmsAndRemindersController,
) : AppRecord

class AlarmsAndRemindersAppListModel(
    private val context: Context,
) : TogglePermissionAppListModel<AlarmsAndRemindersAppRecord> {
    override val pageTitleResId = R.string.alarms_and_reminders_title
    override val switchTitleResId = R.string.alarms_and_reminders_switch_title
    override val footerResId = R.string.alarms_and_reminders_footer_title

    override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
        userIdFlow.map { userId ->
            PackageManagers.getAppOpPermissionPackages(userId, PERMISSION)
        }.combine(appListFlow) { packageNames, appList ->
            appList.map { app ->
                createRecord(app = app, hasRequestPermission = app.packageName in packageNames)
            }
        }

    override fun transformItem(app: ApplicationInfo) =
        createRecord(app = app, hasRequestPermission = app.hasRequestPermission(PERMISSION))

    override fun filter(
        userIdFlow: Flow<Int>,
        recordListFlow: Flow<List<AlarmsAndRemindersAppRecord>>,
    ) = recordListFlow.map { recordList ->
        recordList.filter { it.isChangeable }
    }

    @Composable
    override fun isAllowed(record: AlarmsAndRemindersAppRecord) =
        record.controller.isAllowed.observeAsState()

    override fun isChangeable(record: AlarmsAndRemindersAppRecord) = record.isChangeable

    override fun setAllowed(record: AlarmsAndRemindersAppRecord, newAllowed: Boolean) {
        record.controller.setAllowed(newAllowed)
    }

    private fun createRecord(app: ApplicationInfo, hasRequestPermission: Boolean) =
        AlarmsAndRemindersAppRecord(
            app = app,
            isChangeable = hasRequestPermission && app.isChangeEnabled(),
            controller = AlarmsAndRemindersController(context, app),
        )

    companion object {
        private const val PERMISSION: String = Manifest.permission.SCHEDULE_EXACT_ALARM

        private fun ApplicationInfo.isChangeEnabled(): Boolean =
            CompatChanges.isChangeEnabled(
                AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, packageName, userHandle,
            )
    }
}
+53 −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.settings.spa.app.specialaccess

import android.app.AlarmManager
import android.app.AppOpsManager
import android.app.AppOpsManager.MODE_ALLOWED
import android.app.AppOpsManager.MODE_ERRORED
import android.content.Context
import android.content.pm.ApplicationInfo
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.android.settingslib.spaprivileged.model.app.userId

class AlarmsAndRemindersController(
    context: Context,
    private val app: ApplicationInfo,
) {
    private val alarmManager = context.getSystemService(AlarmManager::class.java)!!
    private val appOpsManager = context.getSystemService(AppOpsManager::class.java)!!

    val isAllowed: LiveData<Boolean>
        get() = _allowed

    fun setAllowed(allowed: Boolean) {
        val mode = if (allowed) MODE_ALLOWED else MODE_ERRORED
        appOpsManager.setUidMode(AppOpsManager.OPSTR_SCHEDULE_EXACT_ALARM, app.uid, mode)
        _allowed.postValue(allowed)
    }

    private val _allowed = object : MutableLiveData<Boolean>() {
        override fun onActive() {
            postValue(alarmManager.hasScheduleExactAlarm(app.packageName, app.userId))
        }

        override fun onInactive() {
        }
    }
}
Loading