1 /* 2 * Copyright (C) 2016 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.server.wm.app; 18 19 import static android.server.wm.app.Components.BROADCAST_RECEIVER_ACTIVITY; 20 import static android.server.wm.app.Components.BroadcastReceiverActivity.ACTION_TRIGGER_BROADCAST; 21 import static android.server.wm.app.Components.BroadcastReceiverActivity.EXTRA_BROADCAST_ORIENTATION; 22 import static android.server.wm.app.Components.BroadcastReceiverActivity.EXTRA_CUTOUT_EXISTS; 23 import static android.server.wm.app.Components.BroadcastReceiverActivity.EXTRA_DISMISS_KEYGUARD; 24 import static android.server.wm.app.Components.BroadcastReceiverActivity.EXTRA_DISMISS_KEYGUARD_METHOD; 25 import static android.server.wm.app.Components.BroadcastReceiverActivity.EXTRA_FINISH_BROADCAST; 26 import static android.server.wm.app.Components.BroadcastReceiverActivity.EXTRA_MOVE_BROADCAST_TO_BACK; 27 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; 28 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; 29 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 30 31 import android.app.Activity; 32 import android.app.KeyguardManager; 33 import android.content.BroadcastReceiver; 34 import android.content.Context; 35 import android.content.Intent; 36 import android.content.IntentFilter; 37 import android.os.Bundle; 38 import android.server.wm.ActivityLauncher; 39 import android.server.wm.TestJournalProvider; 40 import android.util.Log; 41 import android.view.View; 42 import android.view.ViewGroup; 43 import android.view.Window; 44 import android.view.WindowInsets; 45 46 import java.lang.ref.WeakReference; 47 48 /** 49 * Activity that registers broadcast receiver . 50 */ 51 public class BroadcastReceiverActivity extends Activity { 52 private static final String TAG = BroadcastReceiverActivity.class.getSimpleName(); 53 54 private TestBroadcastReceiver mBroadcastReceiver; 55 56 @Override onCreate(Bundle icicle)57 protected void onCreate(Bundle icicle) { 58 super.onCreate(icicle); 59 60 final Object receiver = getLastNonConfigurationInstance(); 61 if (receiver instanceof TestBroadcastReceiver) { 62 mBroadcastReceiver = (TestBroadcastReceiver) receiver; 63 mBroadcastReceiver.associate(this); 64 } else { 65 mBroadcastReceiver = new TestBroadcastReceiver(this); 66 mBroadcastReceiver.register(); 67 } 68 69 // Determine if a display cutout is present 70 final View view = new View(this); 71 getWindow().requestFeature(Window.FEATURE_NO_TITLE); 72 getWindow().getAttributes().layoutInDisplayCutoutMode = 73 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 74 view.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); 75 view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 76 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); 77 setContentView(view); 78 79 WindowInsets insets = getWindowManager().getCurrentWindowMetrics().getWindowInsets(); 80 final boolean cutoutExists = (insets.getDisplayCutout() != null); 81 Log.i(TAG, "cutout=" + cutoutExists); 82 TestJournalProvider.putExtras(BroadcastReceiverActivity.this, 83 bundle -> bundle.putBoolean(EXTRA_CUTOUT_EXISTS, cutoutExists)); 84 } 85 86 @Override onDestroy()87 protected void onDestroy() { 88 super.onDestroy(); 89 mBroadcastReceiver.destroy(); 90 } 91 92 @Override onRetainNonConfigurationInstance()93 public Object onRetainNonConfigurationInstance() { 94 return mBroadcastReceiver; 95 } 96 97 /** 98 * The receiver to perform action on the associated activity. If a broadcast intent is received 99 * while the activity is relaunching, it will be handled after the activity is recreated. 100 */ 101 private static class TestBroadcastReceiver extends BroadcastReceiver { 102 final Context mAppContext; 103 WeakReference<Activity> mRef; 104 TestBroadcastReceiver(Activity activity)105 TestBroadcastReceiver(Activity activity) { 106 mAppContext = activity.getApplicationContext(); 107 associate(activity); 108 } 109 register()110 void register() { 111 mAppContext.registerReceiver(this, new IntentFilter(ACTION_TRIGGER_BROADCAST), 112 Context.RECEIVER_EXPORTED); 113 } 114 associate(Activity activity)115 void associate(Activity activity) { 116 mRef = new WeakReference<>(activity); 117 } 118 destroy()119 void destroy() { 120 final Activity activity = mRef != null ? mRef.get() : null; 121 if (activity != null && activity.isChangingConfigurations()) { 122 // The activity is destroyed for configuration change. Because it will be recreated 123 // immediately the receiver only needs to associate to the new instance. 124 return; 125 } 126 // The case of real finish. 127 mAppContext.unregisterReceiver(this); 128 } 129 130 @Override onReceive(Context context, Intent intent)131 public void onReceive(Context context, Intent intent) { 132 final Bundle extras = intent.getExtras(); 133 if (extras == null) { 134 return; 135 } 136 // Trigger unparcel so the log can show the content of extras. 137 extras.size(); 138 Log.i(TAG, "onReceive: extras=" + extras); 139 140 final Activity activity = mRef.get(); 141 if (activity == null) { 142 return; 143 } 144 145 if (extras.getBoolean(EXTRA_FINISH_BROADCAST)) { 146 activity.finish(); 147 } 148 if (extras.getBoolean(EXTRA_MOVE_BROADCAST_TO_BACK)) { 149 activity.moveTaskToBack(true); 150 } 151 if (extras.containsKey(EXTRA_BROADCAST_ORIENTATION)) { 152 activity.setRequestedOrientation(extras.getInt(EXTRA_BROADCAST_ORIENTATION)); 153 } 154 if (extras.getBoolean(EXTRA_DISMISS_KEYGUARD)) { 155 activity.getWindow().addFlags(FLAG_DISMISS_KEYGUARD); 156 } 157 if (extras.getBoolean(EXTRA_DISMISS_KEYGUARD_METHOD)) { 158 activity.getSystemService(KeyguardManager.class).requestDismissKeyguard(activity, 159 new KeyguardDismissLoggerCallback(context, BROADCAST_RECEIVER_ACTIVITY)); 160 } 161 162 ActivityLauncher.launchActivityFromExtras(activity, extras); 163 } 164 } 165 } 166