1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.customization.module.logging
17 
18 import android.app.WallpaperManager
19 import android.content.Intent
20 import android.stats.style.StyleEnums.APP_LAUNCHED
21 import android.stats.style.StyleEnums.CLOCK_APPLIED
22 import android.stats.style.StyleEnums.CLOCK_COLOR_APPLIED
23 import android.stats.style.StyleEnums.CLOCK_SIZE_APPLIED
24 import android.stats.style.StyleEnums.DARK_THEME_APPLIED
25 import android.stats.style.StyleEnums.GRID_APPLIED
26 import android.stats.style.StyleEnums.LAUNCHED_CROP_AND_SET_ACTION
27 import android.stats.style.StyleEnums.LAUNCHED_DEEP_LINK
28 import android.stats.style.StyleEnums.LAUNCHED_KEYGUARD
29 import android.stats.style.StyleEnums.LAUNCHED_LAUNCHER
30 import android.stats.style.StyleEnums.LAUNCHED_LAUNCH_ICON
31 import android.stats.style.StyleEnums.LAUNCHED_PREFERENCE_UNSPECIFIED
32 import android.stats.style.StyleEnums.LAUNCHED_SETTINGS
33 import android.stats.style.StyleEnums.LAUNCHED_SETTINGS_SEARCH
34 import android.stats.style.StyleEnums.LAUNCHED_SUW
35 import android.stats.style.StyleEnums.LAUNCHED_TIPS
36 import android.stats.style.StyleEnums.LOCK_SCREEN_NOTIFICATION_APPLIED
37 import android.stats.style.StyleEnums.RESET_APPLIED
38 import android.stats.style.StyleEnums.SHORTCUT_APPLIED
39 import android.stats.style.StyleEnums.SNAPSHOT
40 import android.stats.style.StyleEnums.THEMED_ICON_APPLIED
41 import android.stats.style.StyleEnums.THEME_COLOR_APPLIED
42 import android.stats.style.StyleEnums.WALLPAPER_APPLIED
43 import android.stats.style.StyleEnums.WALLPAPER_DESTINATION_HOME_AND_LOCK_SCREEN
44 import android.stats.style.StyleEnums.WALLPAPER_DESTINATION_HOME_SCREEN
45 import android.stats.style.StyleEnums.WALLPAPER_DESTINATION_LOCK_SCREEN
46 import android.stats.style.StyleEnums.WALLPAPER_EFFECT_APPLIED
47 import android.stats.style.StyleEnums.WALLPAPER_EFFECT_FG_DOWNLOAD
48 import android.stats.style.StyleEnums.WALLPAPER_EFFECT_PROBE
49 import android.stats.style.StyleEnums.WALLPAPER_EXPLORE
50 import android.text.TextUtils
51 import com.android.customization.model.color.ColorCustomizationManager
52 import com.android.customization.model.grid.GridOption
53 import com.android.customization.module.logging.ThemesUserEventLogger.ClockSize
54 import com.android.customization.module.logging.ThemesUserEventLogger.ColorSource
55 import com.android.wallpaper.module.WallpaperPreferences
56 import com.android.wallpaper.module.logging.UserEventLogger.EffectStatus
57 import com.android.wallpaper.module.logging.UserEventLogger.SetWallpaperEntryPoint
58 import com.android.wallpaper.module.logging.UserEventLogger.WallpaperDestination
59 import com.android.wallpaper.util.ActivityUtils
60 import com.android.wallpaper.util.LaunchSourceUtils
61 import javax.inject.Inject
62 import javax.inject.Singleton
63 
64 /** StatsLog-backed implementation of [ThemesUserEventLogger]. */
65 @Singleton
66 class ThemesUserEventLoggerImpl
67 @Inject
68 constructor(
69     private val preferences: WallpaperPreferences,
70     private val colorManager: ColorCustomizationManager,
71     private val appSessionId: AppSessionId,
72 ) : ThemesUserEventLogger {
73 
logSnapshotnull74     override fun logSnapshot() {
75         SysUiStatsLogger(SNAPSHOT)
76             .setWallpaperCategoryHash(preferences.getHomeCategoryHash())
77             .setWallpaperIdHash(preferences.getHomeWallpaperIdHash())
78             .setEffectIdHash(preferences.getHomeWallpaperEffectsIdHash())
79             .setLockWallpaperCategoryHash(preferences.getLockCategoryHash())
80             .setLockWallpaperIdHash(preferences.getLockWallpaperIdHash())
81             .setLockEffectIdHash(preferences.getLockWallpaperEffectsIdHash())
82             .setColorSource(colorManager.currentColorSourceForLogging)
83             .setColorVariant(colorManager.currentStyleForLogging)
84             .setSeedColor(colorManager.currentSeedColorForLogging)
85             .log()
86     }
87 
logAppLaunchednull88     override fun logAppLaunched(launchSource: Intent) {
89         SysUiStatsLogger(APP_LAUNCHED)
90             .setAppSessionId(appSessionId.createNewId().getId())
91             .setLaunchedPreference(launchSource.getAppLaunchSource())
92             .log()
93     }
94 
logWallpaperAppliednull95     override fun logWallpaperApplied(
96         collectionId: String?,
97         wallpaperId: String?,
98         effects: String?,
99         @SetWallpaperEntryPoint setWallpaperEntryPoint: Int,
100         @WallpaperDestination destination: Int,
101     ) {
102         val categoryHash = getIdHashCode(collectionId)
103         val wallpaperIdHash = getIdHashCode(wallpaperId)
104         val isHomeWallpaperSet =
105             destination == WALLPAPER_DESTINATION_HOME_SCREEN ||
106                 destination == WALLPAPER_DESTINATION_HOME_AND_LOCK_SCREEN
107         val isLockWallpaperSet =
108             destination == WALLPAPER_DESTINATION_LOCK_SCREEN ||
109                 destination == WALLPAPER_DESTINATION_HOME_AND_LOCK_SCREEN
110         SysUiStatsLogger(WALLPAPER_APPLIED)
111             .setAppSessionId(appSessionId.getId())
112             .setWallpaperCategoryHash(if (isHomeWallpaperSet) categoryHash else 0)
113             .setWallpaperIdHash(if (isHomeWallpaperSet) wallpaperIdHash else 0)
114             .setEffectIdHash(if (isHomeWallpaperSet) getIdHashCode(effects) else 0)
115             .setLockWallpaperCategoryHash(if (isLockWallpaperSet) categoryHash else 0)
116             .setLockWallpaperIdHash(if (isLockWallpaperSet) wallpaperIdHash else 0)
117             .setLockEffectIdHash(if (isLockWallpaperSet) getIdHashCode(effects) else 0)
118             .setSetWallpaperEntryPoint(setWallpaperEntryPoint)
119             .setWallpaperDestination(destination)
120             .log()
121     }
122 
logEffectApplynull123     override fun logEffectApply(
124         effect: String,
125         @EffectStatus status: Int,
126         timeElapsedMillis: Long,
127         resultCode: Int
128     ) {
129         SysUiStatsLogger(WALLPAPER_EFFECT_APPLIED)
130             .setAppSessionId(appSessionId.getId())
131             .setEffectPreference(status)
132             .setEffectIdHash(getIdHashCode(effect))
133             .setTimeElapsed(timeElapsedMillis)
134             .setEffectResultCode(resultCode)
135             .log()
136     }
137 
logEffectProbenull138     override fun logEffectProbe(effect: String, @EffectStatus status: Int) {
139         SysUiStatsLogger(WALLPAPER_EFFECT_PROBE)
140             .setAppSessionId(appSessionId.getId())
141             .setEffectPreference(status)
142             .setEffectIdHash(getIdHashCode(effect))
143             .log()
144     }
145 
logEffectForegroundDownloadnull146     override fun logEffectForegroundDownload(
147         effect: String,
148         @EffectStatus status: Int,
149         timeElapsedMillis: Long
150     ) {
151         SysUiStatsLogger(WALLPAPER_EFFECT_FG_DOWNLOAD)
152             .setAppSessionId(appSessionId.getId())
153             .setEffectPreference(status)
154             .setEffectIdHash(getIdHashCode(effect))
155             .setTimeElapsed(timeElapsedMillis)
156             .log()
157     }
158 
logResetAppliednull159     override fun logResetApplied() {
160         SysUiStatsLogger(RESET_APPLIED).setAppSessionId(appSessionId.getId()).log()
161     }
162 
logWallpaperExploreButtonClickednull163     override fun logWallpaperExploreButtonClicked() {
164         SysUiStatsLogger(WALLPAPER_EXPLORE).setAppSessionId(appSessionId.getId()).log()
165     }
166 
logThemeColorAppliednull167     override fun logThemeColorApplied(
168         @ColorSource source: Int,
169         style: Int,
170         seedColor: Int,
171     ) {
172         SysUiStatsLogger(THEME_COLOR_APPLIED)
173             .setAppSessionId(appSessionId.getId())
174             .setColorSource(source)
175             .setColorVariant(style)
176             .setSeedColor(seedColor)
177             .log()
178     }
179 
logGridAppliednull180     override fun logGridApplied(grid: GridOption) {
181         SysUiStatsLogger(GRID_APPLIED)
182             .setAppSessionId(appSessionId.getId())
183             .setLauncherGrid(grid.getLauncherGridInt())
184             .log()
185     }
186 
logClockAppliednull187     override fun logClockApplied(clockId: String) {
188         SysUiStatsLogger(CLOCK_APPLIED)
189             .setAppSessionId(appSessionId.getId())
190             .setClockPackageHash(getIdHashCode(clockId))
191             .log()
192     }
193 
logClockColorAppliednull194     override fun logClockColorApplied(seedColor: Int) {
195         SysUiStatsLogger(CLOCK_COLOR_APPLIED)
196             .setAppSessionId(appSessionId.getId())
197             .setSeedColor(seedColor)
198             .log()
199     }
200 
logClockSizeAppliednull201     override fun logClockSizeApplied(@ClockSize clockSize: Int) {
202         SysUiStatsLogger(CLOCK_SIZE_APPLIED)
203             .setAppSessionId(appSessionId.getId())
204             .setClockSize(clockSize)
205             .log()
206     }
207 
logThemedIconAppliednull208     override fun logThemedIconApplied(useThemeIcon: Boolean) {
209         SysUiStatsLogger(THEMED_ICON_APPLIED)
210             .setAppSessionId(appSessionId.getId())
211             .setToggleOn(useThemeIcon)
212             .log()
213     }
214 
logLockScreenNotificationAppliednull215     override fun logLockScreenNotificationApplied(showLockScreenNotifications: Boolean) {
216         SysUiStatsLogger(LOCK_SCREEN_NOTIFICATION_APPLIED)
217             .setAppSessionId(appSessionId.getId())
218             .setToggleOn(showLockScreenNotifications)
219             .log()
220     }
221 
logShortcutAppliednull222     override fun logShortcutApplied(shortcut: String, shortcutSlotId: String) {
223         SysUiStatsLogger(SHORTCUT_APPLIED)
224             .setAppSessionId(appSessionId.getId())
225             .setShortcut(shortcut)
226             .setShortcutSlotId(shortcutSlotId)
227             .log()
228     }
229 
logDarkThemeAppliednull230     override fun logDarkThemeApplied(useDarkTheme: Boolean) {
231         SysUiStatsLogger(DARK_THEME_APPLIED)
232             .setAppSessionId(appSessionId.getId())
233             .setToggleOn(useDarkTheme)
234             .log()
235     }
236 
237     /**
238      * The grid integer depends on the column and row numbers. For example: 4x5 is 405 13x37 is 1337
239      * The upper limit for the column / row count is 99.
240      */
GridOptionnull241     private fun GridOption.getLauncherGridInt(): Int {
242         return cols * 100 + rows
243     }
244 
getAppLaunchSourcenull245     private fun Intent.getAppLaunchSource(): Int {
246         return if (hasExtra(LaunchSourceUtils.WALLPAPER_LAUNCH_SOURCE)) {
247             when (getStringExtra(LaunchSourceUtils.WALLPAPER_LAUNCH_SOURCE)) {
248                 LaunchSourceUtils.LAUNCH_SOURCE_LAUNCHER -> LAUNCHED_LAUNCHER
249                 LaunchSourceUtils.LAUNCH_SOURCE_SETTINGS -> LAUNCHED_SETTINGS
250                 LaunchSourceUtils.LAUNCH_SOURCE_SUW -> LAUNCHED_SUW
251                 LaunchSourceUtils.LAUNCH_SOURCE_TIPS -> LAUNCHED_TIPS
252                 LaunchSourceUtils.LAUNCH_SOURCE_DEEP_LINK -> LAUNCHED_DEEP_LINK
253                 LaunchSourceUtils.LAUNCH_SOURCE_KEYGUARD -> LAUNCHED_KEYGUARD
254                 else -> LAUNCHED_PREFERENCE_UNSPECIFIED
255             }
256         } else if (ActivityUtils.isLaunchedFromSettingsSearch(this)) {
257             LAUNCHED_SETTINGS_SEARCH
258         } else if (action != null && action == WallpaperManager.ACTION_CROP_AND_SET_WALLPAPER) {
259             LAUNCHED_CROP_AND_SET_ACTION
260         } else if (categories != null && categories.contains(Intent.CATEGORY_LAUNCHER)) {
261             LAUNCHED_LAUNCH_ICON
262         } else {
263             LAUNCHED_PREFERENCE_UNSPECIFIED
264         }
265     }
266 
267     /** If not set, the output hash is 0. */
WallpaperPreferencesnull268     private fun WallpaperPreferences.getHomeCategoryHash(): Int {
269         return getIdHashCode(getHomeWallpaperCollectionId())
270     }
271 
272     /** If not set, the output hash is 0. */
WallpaperPreferencesnull273     private fun WallpaperPreferences.getHomeWallpaperIdHash(): Int {
274         val remoteId = getHomeWallpaperRemoteId()
275         val wallpaperId =
276             if (!TextUtils.isEmpty(remoteId)) remoteId else getHomeWallpaperServiceName()
277         return getIdHashCode(wallpaperId)
278     }
279 
280     /** If not set, the output hash is 0. */
WallpaperPreferencesnull281     private fun WallpaperPreferences.getLockCategoryHash(): Int {
282         return getIdHashCode(getLockWallpaperCollectionId())
283     }
284 
285     /** If not set, the output hash is 0. */
WallpaperPreferencesnull286     private fun WallpaperPreferences.getLockWallpaperIdHash(): Int {
287         val remoteId = getLockWallpaperRemoteId()
288         val wallpaperId =
289             if (!TextUtils.isEmpty(remoteId)) remoteId else getLockWallpaperServiceName()
290         return getIdHashCode(wallpaperId)
291     }
292 
293     /** If not set, the output hash is 0. */
WallpaperPreferencesnull294     private fun WallpaperPreferences.getHomeWallpaperEffectsIdHash(): Int {
295         return getIdHashCode(getHomeWallpaperEffects())
296     }
297 
298     /** If not set, the output hash is 0. */
getLockWallpaperEffectsIdHashnull299     private fun WallpaperPreferences.getLockWallpaperEffectsIdHash(): Int {
300         return getIdHashCode(getLockWallpaperEffects())
301     }
302 
getIdHashCodenull303     private fun getIdHashCode(id: String?): Int {
304         return id?.hashCode() ?: 0
305     }
306 }
307