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