Loading res/layout/customization_option_entry_app_grid.xml +12 −6 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ android:text="@string/grid_title" android:layout_marginEnd="@dimen/customization_option_entry_text_margin_end" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toStartOf="@+id/option_entry_app_grid_icon" app:layout_constraintEnd_toStartOf="@+id/option_entry_app_grid_icon_container" app:layout_constraintBottom_toTopOf="@+id/option_entry_app_grid_description" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" /> Loading @@ -42,19 +42,25 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="@dimen/customization_option_entry_text_margin_end" android:text="4x4" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/option_entry_app_grid_icon" app:layout_constraintEnd_toStartOf="@+id/option_entry_app_grid_icon_container" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/option_entry_app_grid_title" /> <FrameLayout android:id="@+id/option_entry_app_grid_icon" android:id="@+id/option_entry_app_grid_icon_container" android:layout_width="@dimen/customization_option_entry_icon_size" android:layout_height="@dimen/customization_option_entry_icon_size" android:orientation="horizontal" android:padding="@dimen/customization_option_entry_icon_padding" android:background="@drawable/customization_option_entry_icon_background" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" /> app:layout_constraintBottom_toBottomOf="parent"> <ImageView android:id="@+id/option_entry_app_grid_icon" android:layout_width="match_parent" android:layout_height="match_parent" android:contentDescription="@string/grid_preview_card_content_description" /> </FrameLayout> </androidx.constraintlayout.widget.ConstraintLayout> res/layout/floating_sheet_shape_and_grid.xml 0 → 100644 +54 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?><!-- ~ 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. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingHorizontal="@dimen/floating_sheet_horizontal_padding" android:orientation="vertical"> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingVertical="@dimen/floating_sheet_content_vertical_padding" android:background="@drawable/floating_sheet_content_background" android:clipToPadding="false" android:clipChildren="false"> <!-- This is just an invisible placeholder put in place so that the parent keeps its height stable as the RecyclerView updates from 0 items to N items. Keeping it stable allows the layout logic to keep the size of the preview container stable as well, which bodes well for setting up the SurfaceView for remote rendering without changing its size after the content is loaded into the RecyclerView. It's critical for any TextViews inside the included layout to have text. --> <include layout="@layout/grid_option" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="invisible" /> <androidx.recyclerview.widget.RecyclerView android:id="@id/options" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:clipToPadding="false" android:clipChildren="false" /> </FrameLayout> </LinearLayout> No newline at end of file src/com/android/customization/model/grid/DefaultGridOptionsManager.kt 0 → 100644 +94 −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.customization.model.grid import android.content.ContentValues import android.content.Context import com.android.wallpaper.R import com.android.wallpaper.picker.di.modules.BackgroundDispatcher import com.android.wallpaper.util.PreviewUtils import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject import javax.inject.Singleton import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext @Singleton class DefaultGridOptionsManager @Inject constructor( @ApplicationContext private val context: Context, @BackgroundDispatcher private val bgDispatcher: CoroutineDispatcher, ) : GridOptionsManager2 { private val authorityMetadataKey: String = context.getString(R.string.grid_control_metadata_name) private val previewUtils: PreviewUtils = PreviewUtils(context, authorityMetadataKey) override suspend fun isGridOptionAvailable(): Boolean { return previewUtils.supportsPreview() && (getGridOptions()?.size ?: 0) > 1 } override suspend fun getGridOptions(): List<GridOptionModel>? = withContext(bgDispatcher) { context.contentResolver .query(previewUtils.getUri(LIST_OPTIONS), null, null, null, null) ?.use { cursor -> buildList { while (cursor.moveToNext()) { val rows = cursor.getInt(cursor.getColumnIndex(COL_ROWS)) val cols = cursor.getInt(cursor.getColumnIndex(COL_COLS)) add( GridOptionModel( key = cursor.getString(cursor.getColumnIndex(COL_NAME)), title = context.getString( com.android.themepicker.R.string.grid_title_pattern, cols, rows ), isCurrent = cursor .getString(cursor.getColumnIndex(COL_IS_DEFAULT)) .toBoolean(), rows = rows, cols = cols, ) ) } } } } override fun applyGridOption(gridName: String): Int { return context.contentResolver.update( previewUtils.getUri(DEFAULT_GRID), ContentValues().apply { put("name", gridName) }, null, null, ) } companion object { const val LIST_OPTIONS: String = "list_options" const val DEFAULT_GRID: String = "default_grid" const val COL_NAME: String = "name" const val COL_ROWS: String = "rows" const val COL_COLS: String = "cols" const val COL_IS_DEFAULT: String = "is_default" } } src/com/android/customization/model/grid/GridOptionModel.kt 0 → 100644 +25 −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.customization.model.grid data class GridOptionModel( val key: String, val title: String, val isCurrent: Boolean, val rows: Int, val cols: Int, ) src/com/android/customization/model/grid/GridOptionsManager2.kt 0 → 100644 +26 −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.customization.model.grid interface GridOptionsManager2 { suspend fun isGridOptionAvailable(): Boolean suspend fun getGridOptions(): List<GridOptionModel>? fun applyGridOption(gridName: String): Int } Loading
res/layout/customization_option_entry_app_grid.xml +12 −6 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ android:text="@string/grid_title" android:layout_marginEnd="@dimen/customization_option_entry_text_margin_end" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toStartOf="@+id/option_entry_app_grid_icon" app:layout_constraintEnd_toStartOf="@+id/option_entry_app_grid_icon_container" app:layout_constraintBottom_toTopOf="@+id/option_entry_app_grid_description" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" /> Loading @@ -42,19 +42,25 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="@dimen/customization_option_entry_text_margin_end" android:text="4x4" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/option_entry_app_grid_icon" app:layout_constraintEnd_toStartOf="@+id/option_entry_app_grid_icon_container" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/option_entry_app_grid_title" /> <FrameLayout android:id="@+id/option_entry_app_grid_icon" android:id="@+id/option_entry_app_grid_icon_container" android:layout_width="@dimen/customization_option_entry_icon_size" android:layout_height="@dimen/customization_option_entry_icon_size" android:orientation="horizontal" android:padding="@dimen/customization_option_entry_icon_padding" android:background="@drawable/customization_option_entry_icon_background" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" /> app:layout_constraintBottom_toBottomOf="parent"> <ImageView android:id="@+id/option_entry_app_grid_icon" android:layout_width="match_parent" android:layout_height="match_parent" android:contentDescription="@string/grid_preview_card_content_description" /> </FrameLayout> </androidx.constraintlayout.widget.ConstraintLayout>
res/layout/floating_sheet_shape_and_grid.xml 0 → 100644 +54 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?><!-- ~ 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. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingHorizontal="@dimen/floating_sheet_horizontal_padding" android:orientation="vertical"> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingVertical="@dimen/floating_sheet_content_vertical_padding" android:background="@drawable/floating_sheet_content_background" android:clipToPadding="false" android:clipChildren="false"> <!-- This is just an invisible placeholder put in place so that the parent keeps its height stable as the RecyclerView updates from 0 items to N items. Keeping it stable allows the layout logic to keep the size of the preview container stable as well, which bodes well for setting up the SurfaceView for remote rendering without changing its size after the content is loaded into the RecyclerView. It's critical for any TextViews inside the included layout to have text. --> <include layout="@layout/grid_option" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="invisible" /> <androidx.recyclerview.widget.RecyclerView android:id="@id/options" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:clipToPadding="false" android:clipChildren="false" /> </FrameLayout> </LinearLayout> No newline at end of file
src/com/android/customization/model/grid/DefaultGridOptionsManager.kt 0 → 100644 +94 −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.customization.model.grid import android.content.ContentValues import android.content.Context import com.android.wallpaper.R import com.android.wallpaper.picker.di.modules.BackgroundDispatcher import com.android.wallpaper.util.PreviewUtils import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject import javax.inject.Singleton import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext @Singleton class DefaultGridOptionsManager @Inject constructor( @ApplicationContext private val context: Context, @BackgroundDispatcher private val bgDispatcher: CoroutineDispatcher, ) : GridOptionsManager2 { private val authorityMetadataKey: String = context.getString(R.string.grid_control_metadata_name) private val previewUtils: PreviewUtils = PreviewUtils(context, authorityMetadataKey) override suspend fun isGridOptionAvailable(): Boolean { return previewUtils.supportsPreview() && (getGridOptions()?.size ?: 0) > 1 } override suspend fun getGridOptions(): List<GridOptionModel>? = withContext(bgDispatcher) { context.contentResolver .query(previewUtils.getUri(LIST_OPTIONS), null, null, null, null) ?.use { cursor -> buildList { while (cursor.moveToNext()) { val rows = cursor.getInt(cursor.getColumnIndex(COL_ROWS)) val cols = cursor.getInt(cursor.getColumnIndex(COL_COLS)) add( GridOptionModel( key = cursor.getString(cursor.getColumnIndex(COL_NAME)), title = context.getString( com.android.themepicker.R.string.grid_title_pattern, cols, rows ), isCurrent = cursor .getString(cursor.getColumnIndex(COL_IS_DEFAULT)) .toBoolean(), rows = rows, cols = cols, ) ) } } } } override fun applyGridOption(gridName: String): Int { return context.contentResolver.update( previewUtils.getUri(DEFAULT_GRID), ContentValues().apply { put("name", gridName) }, null, null, ) } companion object { const val LIST_OPTIONS: String = "list_options" const val DEFAULT_GRID: String = "default_grid" const val COL_NAME: String = "name" const val COL_ROWS: String = "rows" const val COL_COLS: String = "cols" const val COL_IS_DEFAULT: String = "is_default" } }
src/com/android/customization/model/grid/GridOptionModel.kt 0 → 100644 +25 −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.customization.model.grid data class GridOptionModel( val key: String, val title: String, val isCurrent: Boolean, val rows: Int, val cols: Int, )
src/com/android/customization/model/grid/GridOptionsManager2.kt 0 → 100644 +26 −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.customization.model.grid interface GridOptionsManager2 { suspend fun isGridOptionAvailable(): Boolean suspend fun getGridOptions(): List<GridOptionModel>? fun applyGridOption(gridName: String): Int }