1 /*
2  * Copyright (C) 2020 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 
17 package com.android.deskclock.controller
18 
19 import android.annotation.TargetApi
20 import android.content.ComponentName
21 import android.content.Context
22 import android.content.Intent
23 import android.content.pm.ShortcutInfo
24 import android.content.pm.ShortcutManager
25 import android.graphics.drawable.Icon
26 import android.os.Build
27 import android.os.UserManager
28 import android.provider.AlarmClock
29 import androidx.annotation.StringRes
30 
31 import com.android.deskclock.DeskClock
32 import com.android.deskclock.HandleApiCalls
33 import com.android.deskclock.HandleShortcuts
34 import com.android.deskclock.LogUtils
35 import com.android.deskclock.R
36 import com.android.deskclock.ScreensaverActivity
37 import com.android.deskclock.data.DataModel
38 import com.android.deskclock.data.Lap
39 import com.android.deskclock.data.Stopwatch
40 import com.android.deskclock.data.StopwatchListener
41 import com.android.deskclock.events.Events
42 import com.android.deskclock.events.ShortcutEventTracker
43 import com.android.deskclock.stopwatch.StopwatchService
44 import com.android.deskclock.uidata.UiDataModel
45 
46 @TargetApi(Build.VERSION_CODES.N_MR1)
47 internal class ShortcutController(val context: Context) {
48     private val mComponentName = ComponentName(context, DeskClock::class.java)
49     private val mShortcutManager = context.getSystemService(ShortcutManager::class.java)
50     private val mUserManager = context.getSystemService(Context.USER_SERVICE) as UserManager
51 
52     init {
53         Controller.getController().addEventTracker(ShortcutEventTracker(context))
54         DataModel.dataModel.addStopwatchListener(StopwatchWatcher())
55     }
56 
57     fun updateShortcuts() {
58         if (!mUserManager.isUserUnlocked()) {
59             LogUtils.i("Skipping shortcut update because user is locked.")
60             return
61         }
62         try {
63             val alarm: ShortcutInfo = createNewAlarmShortcut()
64             val timer: ShortcutInfo = createNewTimerShortcut()
65             val stopwatch: ShortcutInfo = createStopwatchShortcut()
66             val screensaver: ShortcutInfo = createScreensaverShortcut()
67             mShortcutManager.setDynamicShortcuts(listOf(alarm, timer, stopwatch, screensaver))
68         } catch (e: IllegalStateException) {
69             LogUtils.wtf(e)
70         }
71     }
72 
73     private fun createNewAlarmShortcut(): ShortcutInfo {
74         val intent: Intent = Intent(AlarmClock.ACTION_SET_ALARM)
75                 .setClass(context, HandleApiCalls::class.java)
76                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
77                 .putExtra(Events.EXTRA_EVENT_LABEL, R.string.label_shortcut)
78         val setAlarmShortcut = UiDataModel.uiDataModel
79                 .getShortcutId(R.string.category_alarm, R.string.action_create)
80         return ShortcutInfo.Builder(context, setAlarmShortcut)
81                 .setIcon(Icon.createWithResource(context, R.drawable.shortcut_new_alarm))
82                 .setActivity(mComponentName)
83                 .setShortLabel(context.getString(R.string.shortcut_new_alarm_short))
84                 .setLongLabel(context.getString(R.string.shortcut_new_alarm_long))
85                 .setIntent(intent)
86                 .setRank(0)
87                 .build()
88     }
89 
90     private fun createNewTimerShortcut(): ShortcutInfo {
91         val intent: Intent = Intent(AlarmClock.ACTION_SET_TIMER)
92                 .setClass(context, HandleApiCalls::class.java)
93                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
94                 .putExtra(Events.EXTRA_EVENT_LABEL, R.string.label_shortcut)
95         val setTimerShortcut = UiDataModel.uiDataModel
96                 .getShortcutId(R.string.category_timer, R.string.action_create)
97         return ShortcutInfo.Builder(context, setTimerShortcut)
98                 .setIcon(Icon.createWithResource(context, R.drawable.shortcut_new_timer))
99                 .setActivity(mComponentName)
100                 .setShortLabel(context.getString(R.string.shortcut_new_timer_short))
101                 .setLongLabel(context.getString(R.string.shortcut_new_timer_long))
102                 .setIntent(intent)
103                 .setRank(1)
104                 .build()
105     }
106 
107     private fun createStopwatchShortcut(): ShortcutInfo {
108         @StringRes val action: Int = if (DataModel.dataModel.stopwatch.isRunning) {
109             R.string.action_pause
110         } else {
111             R.string.action_start
112         }
113         val shortcutId = UiDataModel.uiDataModel
114                 .getShortcutId(R.string.category_stopwatch, action)
115         val shortcut: ShortcutInfo.Builder = ShortcutInfo.Builder(context, shortcutId)
116                 .setIcon(Icon.createWithResource(context, R.drawable.shortcut_stopwatch))
117                 .setActivity(mComponentName)
118                 .setRank(2)
119         val intent: Intent
120         if (DataModel.dataModel.stopwatch.isRunning) {
121             intent = Intent(StopwatchService.ACTION_PAUSE_STOPWATCH)
122                     .putExtra(Events.EXTRA_EVENT_LABEL, R.string.label_shortcut)
123             shortcut.setShortLabel(context.getString(R.string.shortcut_pause_stopwatch_short))
124                     .setLongLabel(context.getString(R.string.shortcut_pause_stopwatch_long))
125         } else {
126             intent = Intent(StopwatchService.ACTION_START_STOPWATCH)
127                     .putExtra(Events.EXTRA_EVENT_LABEL, R.string.label_shortcut)
128             shortcut.setShortLabel(context.getString(R.string.shortcut_start_stopwatch_short))
129                     .setLongLabel(context.getString(R.string.shortcut_start_stopwatch_long))
130         }
131         intent.setClass(context, HandleShortcuts::class.java)
132                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
133         return shortcut
134                 .setIntent(intent)
135                 .build()
136     }
137 
138     private fun createScreensaverShortcut(): ShortcutInfo {
139         val intent: Intent = Intent(Intent.ACTION_MAIN)
140                 .setClass(context, ScreensaverActivity::class.java)
141                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
142                 .putExtra(Events.EXTRA_EVENT_LABEL, R.string.label_shortcut)
143         val screensaverShortcut = UiDataModel.uiDataModel
144                 .getShortcutId(R.string.category_screensaver, R.string.action_show)
145         return ShortcutInfo.Builder(context, screensaverShortcut)
146                 .setIcon(Icon.createWithResource(context, R.drawable.shortcut_screensaver))
147                 .setActivity(mComponentName)
148                 .setShortLabel(context.getString(R.string.shortcut_start_screensaver_short))
149                 .setLongLabel(context.getString(R.string.shortcut_start_screensaver_long))
150                 .setIntent(intent)
151                 .setRank(3)
152                 .build()
153     }
154 
155     private inner class StopwatchWatcher : StopwatchListener {
156 
157         override fun stopwatchUpdated(before: Stopwatch, after: Stopwatch) {
158             if (!mUserManager.isUserUnlocked()) {
159                 LogUtils.i("Skipping stopwatch shortcut update because user is locked.")
160                 return
161             }
162             try {
163                 mShortcutManager.updateShortcuts(listOf(createStopwatchShortcut()))
164             } catch (e: IllegalStateException) {
165                 LogUtils.wtf(e)
166             }
167         }
168 
169         override fun lapAdded(lap: Lap) {}
170     }
171 }