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