Home | History | Annotate | Download | only in sample
      1 /*
      2  * Copyright (C) 2017 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 package android.car.cluster.sample;
     17 
     18 import static android.car.cluster.CarInstrumentClusterManager.CATEGORY_NAVIGATION;
     19 
     20 import android.app.ActivityOptions;
     21 import android.car.CarNotConnectedException;
     22 import android.car.cluster.ClusterActivityState;
     23 import android.graphics.Rect;
     24 import android.hardware.display.DisplayManager;
     25 import android.hardware.display.DisplayManager.DisplayListener;
     26 import android.hardware.display.VirtualDisplay;
     27 import android.os.Bundle;
     28 import android.os.Handler;
     29 import android.support.v4.app.Fragment;
     30 import android.util.Log;
     31 import android.view.Display;
     32 import android.view.LayoutInflater;
     33 import android.view.Surface;
     34 import android.view.SurfaceHolder;
     35 import android.view.SurfaceHolder.Callback;
     36 import android.view.SurfaceView;
     37 import android.view.View;
     38 import android.view.ViewGroup;
     39 
     40 public class NavigationFragment extends Fragment {
     41     private final static String TAG = "Cluster.NavigationFragment";
     42 
     43     private SurfaceView mSurfaceView;
     44     private DisplayManager mDisplayManager;
     45     private Rect mUnobscuredBounds;
     46 
     47     // Static because we want to keep alive this virtual display when navigating through
     48     // ViewPager (this fragment gets dynamically destroyed and created)
     49     private static VirtualDisplay mVirtualDisplay;
     50     private static int mRegisteredNavDisplayId = Display.INVALID_DISPLAY;
     51 
     52     public NavigationFragment() {
     53         // Required empty public constructor
     54     }
     55 
     56     private final DisplayListener mDisplayListener = new DisplayListener() {
     57         @Override
     58         public void onDisplayAdded(int displayId) {
     59             int navDisplayId = getVirtualDisplayId();
     60             Log.i(TAG, "onDisplayAdded, displayId: " + displayId
     61                     + ", navigation display id: " + navDisplayId);
     62 
     63             if (navDisplayId == displayId) {
     64                 try {
     65                     getService().setClusterActivityLaunchOptions(
     66                             CATEGORY_NAVIGATION,
     67                             ActivityOptions.makeBasic()
     68                                     .setLaunchDisplayId(displayId));
     69                     mRegisteredNavDisplayId = displayId;
     70 
     71                     getService().setClusterActivityState(
     72                             CATEGORY_NAVIGATION,
     73                             ClusterActivityState.create(true, mUnobscuredBounds).toBundle());
     74                 } catch (CarNotConnectedException e) {
     75                     throw new IllegalStateException(
     76                             "Failed to report nav activity cluster launch options", e);
     77                 }
     78             }
     79         }
     80 
     81         @Override
     82         public void onDisplayRemoved(int displayId) {
     83             if (mRegisteredNavDisplayId == displayId) {
     84                 try {
     85                     mRegisteredNavDisplayId = Display.INVALID_DISPLAY;
     86                     getService().setClusterActivityLaunchOptions(
     87                             CATEGORY_NAVIGATION, null);
     88                 } catch (CarNotConnectedException e) {
     89                     // This can happen only during shutdown, ignore.
     90                 }
     91             }
     92         }
     93 
     94         @Override
     95         public void onDisplayChanged(int displayId) {}
     96     };
     97 
     98     @Override
     99     public View onCreateView(LayoutInflater inflater, ViewGroup container,
    100                              Bundle savedInstanceState) {
    101         Log.i(TAG, "onCreateView");
    102         mDisplayManager = getActivity().getSystemService(DisplayManager.class);
    103         mDisplayManager.registerDisplayListener(mDisplayListener, new Handler());
    104 
    105         // Inflate the layout for this fragment
    106         View root = inflater.inflate(R.layout.fragment_navigation, container, false);
    107 
    108         mSurfaceView = root.findViewById(R.id.nav_surface);
    109         mSurfaceView.getHolder().addCallback(new Callback() {
    110             @Override
    111             public void surfaceCreated(SurfaceHolder holder) {
    112                 Log.i(TAG, "surfaceCreated, holder: " + holder);
    113             }
    114 
    115             @Override
    116             public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    117                 Log.i(TAG, "surfaceChanged, holder: " + holder + ", size:" + width + "x" + height
    118                         + ", format:" + format);
    119 
    120                 //Create dummy unobscured area to report to navigation activity.
    121                 mUnobscuredBounds = new Rect(40, 0, width - 80, height - 40);
    122 
    123                 if (mVirtualDisplay == null) {
    124                     mVirtualDisplay = createVirtualDisplay(holder.getSurface(), width, height);
    125                 } else {
    126                     mVirtualDisplay.setSurface(holder.getSurface());
    127                 }
    128             }
    129 
    130             @Override
    131             public void surfaceDestroyed(SurfaceHolder holder) {
    132                 Log.i(TAG, "surfaceDestroyed, holder: " + holder + ", detaching surface from"
    133                         + " display, surface: " + holder.getSurface());
    134                 // detaching surface is similar to turning off the display
    135                 mVirtualDisplay.setSurface(null);
    136             }
    137         });
    138 
    139         return root;
    140     }
    141 
    142     private VirtualDisplay createVirtualDisplay(Surface surface, int width, int height) {
    143         Log.i(TAG, "createVirtualDisplay, surface: " + surface + ", width: " + width
    144                 + "x" + height);
    145         return mDisplayManager.createVirtualDisplay("Cluster-App-VD", width, height, 160, surface,
    146                 DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
    147     }
    148 
    149     @Override
    150     public void onDestroy() {
    151         super.onDestroy();
    152         Log.i(TAG, "onDestroy");
    153     }
    154 
    155     private SampleClusterServiceImpl getService() {
    156         return ((MainClusterActivity) getActivity()).getService();
    157     }
    158 
    159     private int getVirtualDisplayId() {
    160         return (mVirtualDisplay != null && mVirtualDisplay.getDisplay() != null)
    161                 ? mVirtualDisplay.getDisplay().getDisplayId() : Display.INVALID_DISPLAY;
    162     }
    163 }
    164