Home | History | Annotate | Download | only in am
      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.am;
     18 
     19 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
     20 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
     21 import static android.server.am.ActivityLauncher.KEY_DISPLAY_ID;
     22 import static android.server.am.ActivityLauncher.KEY_LAUNCH_ACTIVITY;
     23 import static android.server.am.ActivityLauncher.KEY_TARGET_COMPONENT;
     24 import static android.server.am.ComponentNameUtils.getActivityName;
     25 import static android.server.am.Components.VirtualDisplayActivity.COMMAND_CREATE_DISPLAY;
     26 import static android.server.am.Components.VirtualDisplayActivity.COMMAND_DESTROY_DISPLAY;
     27 import static android.server.am.Components.VirtualDisplayActivity.COMMAND_RESIZE_DISPLAY;
     28 import static android.server.am.Components.VirtualDisplayActivity.KEY_CAN_SHOW_WITH_INSECURE_KEYGUARD;
     29 import static android.server.am.Components.VirtualDisplayActivity.KEY_COMMAND;
     30 import static android.server.am.Components.VirtualDisplayActivity.KEY_COUNT;
     31 import static android.server.am.Components.VirtualDisplayActivity.KEY_DENSITY_DPI;
     32 import static android.server.am.Components.VirtualDisplayActivity.KEY_LAUNCH_TARGET_COMPONENT;
     33 import static android.server.am.Components.VirtualDisplayActivity.KEY_PUBLIC_DISPLAY;
     34 import static android.server.am.Components.VirtualDisplayActivity.KEY_RESIZE_DISPLAY;
     35 import static android.server.am.Components.VirtualDisplayActivity.VIRTUAL_DISPLAY_PREFIX;
     36 
     37 import android.app.Activity;
     38 import android.content.ComponentName;
     39 import android.content.Intent;
     40 import android.hardware.display.DisplayManager;
     41 import android.hardware.display.VirtualDisplay;
     42 import android.os.Bundle;
     43 import android.util.Log;
     44 import android.view.Surface;
     45 import android.view.SurfaceHolder;
     46 import android.view.SurfaceView;
     47 import android.view.ViewGroup;
     48 
     49 import java.util.HashMap;
     50 
     51 /**
     52  * Activity that is able to create and destroy a virtual display.
     53  */
     54 public class VirtualDisplayActivity extends Activity implements SurfaceHolder.Callback {
     55     private static final String TAG = VirtualDisplayActivity.class.getSimpleName();
     56 
     57     private static final int DEFAULT_DENSITY_DPI = 160;
     58 
     59     // Container for details about a pending virtual display creation request.
     60     private static class VirtualDisplayRequest {
     61         final SurfaceView surfaceView;
     62         final Bundle extras;
     63 
     64         VirtualDisplayRequest(SurfaceView surfaceView, Bundle extras) {
     65             this.surfaceView = surfaceView;
     66             this.extras = extras;
     67         }
     68     }
     69 
     70     // Container to hold association between an active virtual display and surface view.
     71     private static class VirtualDisplayEntry {
     72         final VirtualDisplay display;
     73         final SurfaceView surfaceView;
     74         final boolean resizeDisplay;
     75         final int density;
     76 
     77         VirtualDisplayEntry(VirtualDisplay display, SurfaceView surfaceView, int density,
     78                 boolean resizeDisplay) {
     79             this.display = display;
     80             this.surfaceView = surfaceView;
     81             this.density = density;
     82             this.resizeDisplay = resizeDisplay;
     83         }
     84     }
     85 
     86     private final HashMap<Surface, VirtualDisplayRequest> mPendingDisplayRequests = new HashMap<>();
     87     private final HashMap<Surface, VirtualDisplayEntry> mVirtualDisplays = new HashMap<>();
     88     private DisplayManager mDisplayManager;
     89 
     90     @Override
     91     protected void onCreate(Bundle savedInstanceState) {
     92         super.onCreate(savedInstanceState);
     93         setContentView(R.layout.virtual_display_layout);
     94 
     95         mDisplayManager = (DisplayManager) getSystemService(DISPLAY_SERVICE);
     96     }
     97 
     98     @Override
     99     protected void onNewIntent(Intent intent) {
    100         super.onNewIntent(intent);
    101         final Bundle extras = intent.getExtras();
    102         if (extras == null) {
    103             return;
    104         }
    105 
    106         String command = extras.getString(KEY_COMMAND);
    107         switch (command) {
    108             case COMMAND_CREATE_DISPLAY:
    109                 createVirtualDisplay(extras);
    110                 break;
    111             case COMMAND_DESTROY_DISPLAY:
    112                 destroyVirtualDisplays();
    113                 break;
    114             case COMMAND_RESIZE_DISPLAY:
    115                 resizeDisplay();
    116                 break;
    117         }
    118     }
    119 
    120     @Override
    121     protected void onDestroy() {
    122         super.onDestroy();
    123         destroyVirtualDisplays();
    124     }
    125 
    126     private void createVirtualDisplay(Bundle extras) {
    127         final int requestedCount = extras.getInt(KEY_COUNT, 1);
    128         Log.d(TAG, "createVirtualDisplays. requested count:" + requestedCount);
    129 
    130         for (int displayCount = 0; displayCount < requestedCount; ++displayCount) {
    131             final ViewGroup root = findViewById(android.R.id.content);
    132             final SurfaceView surfaceView = new SurfaceView(this);
    133             surfaceView.setLayoutParams(new ViewGroup.LayoutParams(
    134                     ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    135             surfaceView.getHolder().addCallback(this);
    136             mPendingDisplayRequests.put(surfaceView.getHolder().getSurface(),
    137                     new VirtualDisplayRequest(surfaceView, extras));
    138             root.addView(surfaceView);
    139         }
    140     }
    141 
    142     private void destroyVirtualDisplays() {
    143         Log.d(TAG, "destroyVirtualDisplays");
    144         final ViewGroup root = findViewById(android.R.id.content);
    145 
    146         for (VirtualDisplayEntry entry : mVirtualDisplays.values()) {
    147             Log.d(TAG, "destroying:" + entry.display);
    148             entry.display.release();
    149             root.removeView(entry.surfaceView);
    150         }
    151 
    152         mPendingDisplayRequests.clear();
    153         mVirtualDisplays.clear();
    154     }
    155 
    156     @Override
    157     public void surfaceCreated(SurfaceHolder surfaceHolder) {
    158         final VirtualDisplayRequest entry =
    159                 mPendingDisplayRequests.remove(surfaceHolder.getSurface());
    160 
    161         if (entry == null) {
    162             return;
    163         }
    164 
    165         final int densityDpi = entry.extras.getInt(KEY_DENSITY_DPI, DEFAULT_DENSITY_DPI);
    166         final boolean resizeDisplay = entry.extras.getBoolean(KEY_RESIZE_DISPLAY);
    167         final String launchComponentName = entry.extras.getString(KEY_LAUNCH_TARGET_COMPONENT);
    168         final Surface surface = surfaceHolder.getSurface();
    169 
    170         // Initially, the surface will not have a set width or height so rely on the parent.
    171         // This should be accurate with match parent on both params.
    172         final int width = surfaceHolder.getSurfaceFrame().width();
    173         final int height = surfaceHolder.getSurfaceFrame().height();
    174 
    175         int flags = 0;
    176 
    177         final boolean canShowWithInsecureKeyguard
    178                 = entry.extras.getBoolean(KEY_CAN_SHOW_WITH_INSECURE_KEYGUARD);
    179         if (canShowWithInsecureKeyguard) {
    180             flags |= 1 << 5; // VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD
    181         }
    182 
    183         final boolean publicDisplay = entry.extras.getBoolean(KEY_PUBLIC_DISPLAY);
    184         if (publicDisplay) {
    185             flags |= VIRTUAL_DISPLAY_FLAG_PUBLIC | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
    186         }
    187 
    188         Log.d(TAG, "createVirtualDisplay: " + width + "x" + height + ", dpi: "
    189                 + densityDpi + ", canShowWithInsecureKeyguard=" + canShowWithInsecureKeyguard
    190                 + ", publicDisplay=" + publicDisplay);
    191         try {
    192             VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(
    193                     VIRTUAL_DISPLAY_PREFIX + mVirtualDisplays.size(), width,
    194                     height, densityDpi, surface, flags);
    195             mVirtualDisplays.put(surface,
    196                     new VirtualDisplayEntry(virtualDisplay, entry.surfaceView, densityDpi,
    197                             resizeDisplay));
    198             if (launchComponentName != null) {
    199                 final ComponentName targetActivity =
    200                         ComponentName.unflattenFromString(launchComponentName);
    201                 final int displayId = virtualDisplay.getDisplay().getDisplayId();
    202                 Log.d(TAG, "Launch activity after display created: activityName="
    203                         + getActivityName(targetActivity) + ", displayId=" + displayId);
    204                 launchActivity(targetActivity, displayId);
    205             }
    206         } catch (IllegalArgumentException e) {
    207             final ViewGroup root = findViewById(android.R.id.content);
    208             // This is expected when trying to create show-when-locked public display.
    209             root.removeView(entry.surfaceView);
    210         }
    211     }
    212 
    213     @Override
    214     public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
    215         final VirtualDisplayEntry entry = mVirtualDisplays.get(surfaceHolder.getSurface());
    216 
    217         if (entry != null && entry.resizeDisplay) {
    218             entry.display.resize(width, height, entry.density);
    219         }
    220     }
    221 
    222     @Override
    223     public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
    224     }
    225 
    226     /** Resize virtual display to half of the surface frame size. */
    227     private void resizeDisplay() {
    228         final VirtualDisplayEntry vd = (VirtualDisplayEntry) mVirtualDisplays.values().toArray()[0];
    229         final SurfaceHolder surfaceHolder = vd.surfaceView.getHolder();
    230         vd.display.resize(surfaceHolder.getSurfaceFrame().width() / 2,
    231                 surfaceHolder.getSurfaceFrame().height() / 2, vd.density);
    232     }
    233 
    234     private void launchActivity(ComponentName activityName, int displayId) {
    235         final Bundle extras = new Bundle();
    236         extras.putBoolean(KEY_LAUNCH_ACTIVITY, true);
    237         extras.putString(KEY_TARGET_COMPONENT, getActivityName(activityName));
    238         extras.putInt(KEY_DISPLAY_ID, displayId);
    239         ActivityLauncher.launchActivityFromExtras(this, extras);
    240     }
    241 }
    242