1 /*
2  * Copyright (C) 2023 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.sdksandbox;
18 
19 import static android.app.sdksandbox.SdkSandboxManager.EXTRA_SANDBOXED_ACTIVITY_HANDLER;
20 
21 import android.annotation.NonNull;
22 import android.app.Activity;
23 import android.app.sdksandbox.SandboxedSdkContext;
24 import android.app.sdksandbox.SdkSandboxManager;
25 import android.app.sdksandbox.sdkprovider.SdkSandboxActivityRegistry;
26 import android.content.Context;
27 import android.os.Build;
28 import android.os.Bundle;
29 import android.util.Log;
30 import android.view.Window;
31 
32 import androidx.annotation.RequiresApi;
33 
34 import com.android.internal.annotations.VisibleForTesting;
35 
36 /**
37  * Activity to start for SDKs running in the SDK Runtime.
38  *
39  * <p>It should be created when an {@link android.content.Intent} with action name ({@link
40  * SdkSandboxManager#ACTION_START_SANDBOXED_ACTIVITY}) is started.
41  *
42  * @hide
43  */
44 public class SandboxedActivity extends Activity {
45     private static final String TAG = "SandboxedActivity";
46     private final Injector mInjector;
47 
SandboxedActivity()48     public SandboxedActivity() {
49         this(new Injector());
50     }
51 
52     @VisibleForTesting
SandboxedActivity(Injector injector)53     SandboxedActivity(Injector injector) {
54         super();
55         mInjector = injector;
56     }
57 
58     /**
59      * Wraps the base context in an internal {@link android.content.ContextWrapper} instance before
60      * attaching it.
61      */
62     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
63     @Override
attachBaseContext(Context newBase)64     protected void attachBaseContext(Context newBase) {
65         SdkSandboxActivityRegistry registry = mInjector.getSdkSandboxActivityRegistry();
66         final SandboxedSdkContext sdkContext = registry.getSdkContext(this.getIntent());
67         if (sdkContext == null) {
68             Log.w(TAG, "Failed to get SDK Context for the passed intent");
69             super.attachBaseContext(newBase);
70             return;
71         }
72         super.attachBaseContext(sdkContext.createContextWithNewBase(newBase));
73     }
74 
75     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
76     @Override
onCreate(@onNull Bundle savedInstanceState)77     public void onCreate(@NonNull Bundle savedInstanceState) {
78         super.onCreate(savedInstanceState);
79         requestWindowFeature(Window.FEATURE_NO_TITLE);
80 
81         notifySdkOnActivityCreation();
82     }
83 
84     /**
85      * Notify the SDK by calling {@link
86      * android.app.sdksandbox.sdkprovider.SdkSandboxActivityHandler#onActivityCreated(Activity)}.
87      */
88     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
notifySdkOnActivityCreation()89     public void notifySdkOnActivityCreation() {
90         // TODO(b/326974007): log SandboxActivity creation latency here instead of
91         // SdkSandboxActivityRegistry.
92         SdkSandboxActivityRegistry registry = mInjector.getSdkSandboxActivityRegistry();
93         try {
94             registry.notifyOnActivityCreation(this.getIntent(), this);
95         } catch (Exception e) {
96             Log.e(TAG, "Failed to start the SandboxedActivity and going to finish it: ", e);
97             finish();
98         }
99     }
100 
101     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
102     @NonNull
getSandboxedActivityHandlerKey()103     String getSandboxedActivityHandlerKey() {
104         return EXTRA_SANDBOXED_ACTIVITY_HANDLER;
105     }
106 
107     static class Injector {
getSdkSandboxActivityRegistry()108         SdkSandboxActivityRegistry getSdkSandboxActivityRegistry() {
109             return SdkSandboxActivityRegistry.getInstance();
110         }
111     }
112 }
113