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 android.service.dreams;
18 
19 import android.annotation.Nullable;
20 import android.app.Activity;
21 import android.content.Intent;
22 import android.os.Bundle;
23 import android.text.TextUtils;
24 
25 import com.android.internal.annotations.VisibleForTesting;
26 
27 /**
28  * The Activity used by the {@link DreamService} to draw screensaver content
29  * on the screen. This activity runs in dream application's process, but is started by a
30  * specialized method: {@link com.android.server.wm.ActivityTaskManagerService#startDreamActivity}.
31  * Hence, it does not have to be declared in the dream application's manifest.
32  *
33  * We use an activity as the dream canvas, because it interacts easier with other activities on
34  * the screen (compared to a hover window). However, the DreamService is in charge of the dream and
35  * it receives all Window.Callbacks from its main window. Since a window can have only one callback
36  * receiver, the activity will not receive any window callbacks.
37  *
38  * Prior to the DreamActivity, the DreamService used to work with a hovering window and give the
39  * screensaver application control over that window. The DreamActivity is a replacement to that
40  * hover window. Using an activity allows for better-defined interactions with the rest of the
41  * activities on screen. The switch to DreamActivity should be transparent to the screensaver
42  * application, i.e. the application will still use DreamService APIs and not notice that the
43  * system is using an activity behind the scenes.
44  *
45  * @hide
46  */
47 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
48 public class DreamActivity extends Activity {
49     static final String EXTRA_CALLBACK = "binder";
50     static final String EXTRA_DREAM_TITLE = "title";
51     @Nullable
52     private DreamService.DreamActivityCallbacks mCallback;
53 
DreamActivity()54     public DreamActivity() {}
55 
56     @Override
onCreate(@ullable Bundle bundle)57     public void onCreate(@Nullable Bundle bundle) {
58         super.onCreate(bundle);
59 
60         final String title = getTitle(getIntent());
61         if (!TextUtils.isEmpty(title)) {
62             setTitle(title);
63         }
64 
65         mCallback = getCallback(getIntent());
66 
67         if (mCallback == null) {
68             finishAndRemoveTask();
69             return;
70         }
71 
72         mCallback.onActivityCreated(this);
73     }
74 
75     /**
76      * Sets the title of the dream in the intent for starting the {@link DreamActivity}.
77      */
setTitle(Intent intent, CharSequence title)78     public static void setTitle(Intent intent, CharSequence title) {
79         if (TextUtils.isEmpty(title)) {
80             return;
81         }
82 
83         intent.putExtra(DreamActivity.EXTRA_DREAM_TITLE, title);
84     }
85 
86     /**
87      * Gets the title of the dream from the intent used to start the {@link DreamActivity}.
88      */
getTitle(Intent intent)89     public static String getTitle(Intent intent) {
90         return intent.getStringExtra(EXTRA_DREAM_TITLE);
91     }
92 
93     /**
94      * Sets the dream callback in the intent for starting the {@link DreamActivity}.
95      */
setCallback(Intent intent, DreamService.DreamActivityCallbacks callback)96     public static void setCallback(Intent intent, DreamService.DreamActivityCallbacks callback) {
97         intent.putExtra(DreamActivity.EXTRA_CALLBACK, callback);
98     }
99 
100     /**
101      * Retrieves the dream callback from the intent used to start the {@link DreamActivity}.
102      */
getCallback(Intent intent)103     public static DreamService.DreamActivityCallbacks getCallback(Intent intent) {
104         final Object binder = intent.getExtras().getBinder(EXTRA_CALLBACK);
105 
106         return (binder instanceof DreamService.DreamActivityCallbacks)
107                 ? (DreamService.DreamActivityCallbacks) binder
108                 : null;
109     }
110 
111     @Override
onDestroy()112     public void onDestroy() {
113         if (mCallback != null) {
114             mCallback.onActivityDestroyed();
115         }
116 
117         super.onDestroy();
118     }
119 }
120