Loading libs/WindowManager/Shell/Android.bp +12 −0 Original line number Diff line number Diff line Loading @@ -166,6 +166,16 @@ java_library { }, } java_library { name: "WindowManager-Shell-lite-proto", srcs: ["src/com/android/wm/shell/desktopmode/education/data/proto/**/*.proto"], proto: { type: "lite", }, } filegroup { name: "wm_shell-shared-aidls", Loading Loading @@ -215,6 +225,7 @@ android_library { "androidx.core_core-animation", "androidx.core_core-ktx", "androidx.arch.core_core-runtime", "androidx.datastore_datastore", "androidx.compose.material3_material3", "androidx-constraintlayout_constraintlayout", "androidx.dynamicanimation_dynamicanimation", Loading @@ -225,6 +236,7 @@ android_library { "//frameworks/libs/systemui:iconloader_base", "com_android_wm_shell_flags_lib", "WindowManager-Shell-proto", "WindowManager-Shell-lite-proto", "WindowManager-Shell-shared", "perfetto_trace_java_protos", "dagger2", Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +8 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator; import com.android.wm.shell.desktopmode.SpringDragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.education.data.AppHandleEducationDatastoreRepository; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.draganddrop.GlobalDragListener; import com.android.wm.shell.freeform.FreeformComponents; Loading Loading @@ -679,6 +680,13 @@ public abstract class WMShellModule { return new DesktopModeEventLogger(); } @WMSingleton @Provides static AppHandleEducationDatastoreRepository provideAppHandleEducationDatastoreRepository( Context context) { return new AppHandleEducationDatastoreRepository(context); } // // Drag and drop // Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppHandleEducationDatastoreRepository.kt 0 → 100644 +81 −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.wm.shell.desktopmode.education.data import android.content.Context import android.util.Log import androidx.datastore.core.CorruptionException import androidx.datastore.core.DataStore import androidx.datastore.core.DataStoreFactory import androidx.datastore.core.Serializer import androidx.datastore.dataStore import androidx.datastore.dataStoreFile import com.android.framework.protobuf.InvalidProtocolBufferException import com.android.internal.annotations.VisibleForTesting import java.io.InputStream import java.io.OutputStream import kotlinx.coroutines.flow.first /** * Manages interactions with the App Handle education datastore. * * This class provides a layer of abstraction between the UI/business logic and the underlying * DataStore. */ class AppHandleEducationDatastoreRepository @VisibleForTesting constructor(private val dataStore: DataStore<WindowingEducationProto>) { constructor( context: Context ) : this( DataStoreFactory.create( serializer = WindowingEducationProtoSerializer, produceFile = { context.dataStoreFile(APP_HANDLE_EDUCATION_DATASTORE_FILEPATH) })) /** * Reads and returns the [WindowingEducationProto] Proto object from the DataStore. If the * DataStore is empty or there's an error reading, it returns the default value of Proto. */ suspend fun windowingEducationProto(): WindowingEducationProto = try { dataStore.data.first() } catch (e: Exception) { Log.e(TAG, "Unable to read from datastore") WindowingEducationProto.getDefaultInstance() } companion object { private const val TAG = "AppHandleEducationDatastoreRepository" private const val APP_HANDLE_EDUCATION_DATASTORE_FILEPATH = "app_handle_education.pb" object WindowingEducationProtoSerializer : Serializer<WindowingEducationProto> { override val defaultValue: WindowingEducationProto = WindowingEducationProto.getDefaultInstance() override suspend fun readFrom(input: InputStream): WindowingEducationProto = try { WindowingEducationProto.parseFrom(input) } catch (exception: InvalidProtocolBufferException) { throw CorruptionException("Cannot read proto.", exception) } override suspend fun writeTo(windowingProto: WindowingEducationProto, output: OutputStream) = windowingProto.writeTo(output) } } } libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/proto/windowing_education.proto 0 → 100644 +39 −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. */ syntax = "proto2"; option java_package = "com.android.wm.shell.desktopmode.education.data"; option java_multiple_files = true; // Desktop Windowing education data message WindowingEducationProto { // Timestamp in milliseconds of when the education was last viewed. optional int64 education_viewed_timestamp_millis = 1; // Timestamp in milliseconds of when the feature was last used. optional int64 feature_used_timestamp_millis = 2; oneof education_data { // Fields specific to app handle education AppHandleEducation app_handle_education = 3; } message AppHandleEducation { // Map that stores app launch count for corresponding package map<string, int32> app_usage_stats = 1; // Timestamp of when app_usage_stats was last cached optional int64 app_usage_stats_last_update_timestamp_millis = 2; } } No newline at end of file libs/WindowManager/Shell/tests/unittest/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,8 @@ android_test { "androidx.test.runner", "androidx.test.rules", "androidx.test.ext.junit", "androidx.datastore_datastore", "kotlinx_coroutines_test", "androidx.dynamicanimation_dynamicanimation", "dagger2", "frameworks-base-testutils", Loading Loading
libs/WindowManager/Shell/Android.bp +12 −0 Original line number Diff line number Diff line Loading @@ -166,6 +166,16 @@ java_library { }, } java_library { name: "WindowManager-Shell-lite-proto", srcs: ["src/com/android/wm/shell/desktopmode/education/data/proto/**/*.proto"], proto: { type: "lite", }, } filegroup { name: "wm_shell-shared-aidls", Loading Loading @@ -215,6 +225,7 @@ android_library { "androidx.core_core-animation", "androidx.core_core-ktx", "androidx.arch.core_core-runtime", "androidx.datastore_datastore", "androidx.compose.material3_material3", "androidx-constraintlayout_constraintlayout", "androidx.dynamicanimation_dynamicanimation", Loading @@ -225,6 +236,7 @@ android_library { "//frameworks/libs/systemui:iconloader_base", "com_android_wm_shell_flags_lib", "WindowManager-Shell-proto", "WindowManager-Shell-lite-proto", "WindowManager-Shell-shared", "perfetto_trace_java_protos", "dagger2", Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +8 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator; import com.android.wm.shell.desktopmode.SpringDragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.education.data.AppHandleEducationDatastoreRepository; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.draganddrop.GlobalDragListener; import com.android.wm.shell.freeform.FreeformComponents; Loading Loading @@ -679,6 +680,13 @@ public abstract class WMShellModule { return new DesktopModeEventLogger(); } @WMSingleton @Provides static AppHandleEducationDatastoreRepository provideAppHandleEducationDatastoreRepository( Context context) { return new AppHandleEducationDatastoreRepository(context); } // // Drag and drop // Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppHandleEducationDatastoreRepository.kt 0 → 100644 +81 −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.wm.shell.desktopmode.education.data import android.content.Context import android.util.Log import androidx.datastore.core.CorruptionException import androidx.datastore.core.DataStore import androidx.datastore.core.DataStoreFactory import androidx.datastore.core.Serializer import androidx.datastore.dataStore import androidx.datastore.dataStoreFile import com.android.framework.protobuf.InvalidProtocolBufferException import com.android.internal.annotations.VisibleForTesting import java.io.InputStream import java.io.OutputStream import kotlinx.coroutines.flow.first /** * Manages interactions with the App Handle education datastore. * * This class provides a layer of abstraction between the UI/business logic and the underlying * DataStore. */ class AppHandleEducationDatastoreRepository @VisibleForTesting constructor(private val dataStore: DataStore<WindowingEducationProto>) { constructor( context: Context ) : this( DataStoreFactory.create( serializer = WindowingEducationProtoSerializer, produceFile = { context.dataStoreFile(APP_HANDLE_EDUCATION_DATASTORE_FILEPATH) })) /** * Reads and returns the [WindowingEducationProto] Proto object from the DataStore. If the * DataStore is empty or there's an error reading, it returns the default value of Proto. */ suspend fun windowingEducationProto(): WindowingEducationProto = try { dataStore.data.first() } catch (e: Exception) { Log.e(TAG, "Unable to read from datastore") WindowingEducationProto.getDefaultInstance() } companion object { private const val TAG = "AppHandleEducationDatastoreRepository" private const val APP_HANDLE_EDUCATION_DATASTORE_FILEPATH = "app_handle_education.pb" object WindowingEducationProtoSerializer : Serializer<WindowingEducationProto> { override val defaultValue: WindowingEducationProto = WindowingEducationProto.getDefaultInstance() override suspend fun readFrom(input: InputStream): WindowingEducationProto = try { WindowingEducationProto.parseFrom(input) } catch (exception: InvalidProtocolBufferException) { throw CorruptionException("Cannot read proto.", exception) } override suspend fun writeTo(windowingProto: WindowingEducationProto, output: OutputStream) = windowingProto.writeTo(output) } } }
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/proto/windowing_education.proto 0 → 100644 +39 −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. */ syntax = "proto2"; option java_package = "com.android.wm.shell.desktopmode.education.data"; option java_multiple_files = true; // Desktop Windowing education data message WindowingEducationProto { // Timestamp in milliseconds of when the education was last viewed. optional int64 education_viewed_timestamp_millis = 1; // Timestamp in milliseconds of when the feature was last used. optional int64 feature_used_timestamp_millis = 2; oneof education_data { // Fields specific to app handle education AppHandleEducation app_handle_education = 3; } message AppHandleEducation { // Map that stores app launch count for corresponding package map<string, int32> app_usage_stats = 1; // Timestamp of when app_usage_stats was last cached optional int64 app_usage_stats_last_update_timestamp_millis = 2; } } No newline at end of file
libs/WindowManager/Shell/tests/unittest/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,8 @@ android_test { "androidx.test.runner", "androidx.test.rules", "androidx.test.ext.junit", "androidx.datastore_datastore", "kotlinx_coroutines_test", "androidx.dynamicanimation_dynamicanimation", "dagger2", "frameworks-base-testutils", Loading