1905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev/*
2905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * Copyright (C) 2017 The Android Open Source Project
3905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev *
4905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * Licensed under the Apache License, Version 2.0 (the "License");
5905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * you may not use this file except in compliance with the License.
6905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * You may obtain a copy of the License at
7905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev *
8905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev *      http://www.apache.org/licenses/LICENSE-2.0
9905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev *
10905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * Unless required by applicable law or agreed to in writing, software
11905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * distributed under the License is distributed on an "AS IS" BASIS,
12905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * See the License for the specific language governing permissions and
14905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * limitations under the License.
15905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev */
16905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevpackage android.car.cluster.sample;
17905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
18905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport static android.car.cluster.CarInstrumentClusterManager.CATEGORY_NAVIGATION;
19905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
20905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.app.ActivityOptions;
21905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.car.CarNotConnectedException;
22905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.car.cluster.ClusterActivityState;
23905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.graphics.Rect;
24905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.hardware.display.DisplayManager;
25905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.hardware.display.DisplayManager.DisplayListener;
26905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.hardware.display.VirtualDisplay;
27905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.os.Bundle;
28905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.os.Handler;
29905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.support.v4.app.Fragment;
30905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.util.Log;
31905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.view.Display;
32905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.view.LayoutInflater;
33905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.view.Surface;
34905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.view.SurfaceHolder;
35905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.view.SurfaceHolder.Callback;
36905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.view.SurfaceView;
37905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.view.View;
38905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.view.ViewGroup;
39905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
40905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevpublic class NavigationFragment extends Fragment {
41905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    private final static String TAG = "Cluster.NavigationFragment";
42905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
43905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    private SurfaceView mSurfaceView;
44905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    private DisplayManager mDisplayManager;
45905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    private Rect mUnobscuredBounds;
46905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
47905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    // Static because we want to keep alive this virtual display when navigating through
48905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    // ViewPager (this fragment gets dynamically destroyed and created)
49905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    private static VirtualDisplay mVirtualDisplay;
50905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    private static int mRegisteredNavDisplayId = Display.INVALID_DISPLAY;
51905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
52905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    public NavigationFragment() {
53905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        // Required empty public constructor
54905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    }
55905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
56905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    private final DisplayListener mDisplayListener = new DisplayListener() {
57905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        @Override
58905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        public void onDisplayAdded(int displayId) {
59905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev            int navDisplayId = getVirtualDisplayId();
60905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev            Log.i(TAG, "onDisplayAdded, displayId: " + displayId
61905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                    + ", navigation display id: " + navDisplayId);
62905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
63905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev            if (navDisplayId == displayId) {
64905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                try {
65905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                    getService().setClusterActivityLaunchOptions(
66905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                            CATEGORY_NAVIGATION,
67905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                            ActivityOptions.makeBasic()
68905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                                    .setLaunchDisplayId(displayId));
69905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                    mRegisteredNavDisplayId = displayId;
70905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
71905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                    getService().setClusterActivityState(
72905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                            CATEGORY_NAVIGATION,
73905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                            ClusterActivityState.create(true, mUnobscuredBounds).toBundle());
74905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                } catch (CarNotConnectedException e) {
75905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                    throw new IllegalStateException(
76905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                            "Failed to report nav activity cluster launch options", e);
77905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                }
78905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev            }
79905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        }
80905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
81905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        @Override
82905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        public void onDisplayRemoved(int displayId) {
83905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev            if (mRegisteredNavDisplayId == displayId) {
84905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                try {
85905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                    mRegisteredNavDisplayId = Display.INVALID_DISPLAY;
86905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                    getService().setClusterActivityLaunchOptions(
87905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                            CATEGORY_NAVIGATION, null);
88905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                } catch (CarNotConnectedException e) {
89905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                    // This can happen only during shutdown, ignore.
90905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                }
91905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev            }
92905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        }
93905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
94905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        @Override
95905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        public void onDisplayChanged(int displayId) {}
96905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    };
97905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
98905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    @Override
99905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    public View onCreateView(LayoutInflater inflater, ViewGroup container,
100905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                             Bundle savedInstanceState) {
101905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        Log.i(TAG, "onCreateView");
102905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        mDisplayManager = getActivity().getSystemService(DisplayManager.class);
103905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        mDisplayManager.registerDisplayListener(mDisplayListener, new Handler());
104905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
105905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        // Inflate the layout for this fragment
106905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        View root = inflater.inflate(R.layout.fragment_navigation, container, false);
107905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
108905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        mSurfaceView = root.findViewById(R.id.nav_surface);
109905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        mSurfaceView.getHolder().addCallback(new Callback() {
110905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev            @Override
111905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev            public void surfaceCreated(SurfaceHolder holder) {
112905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                Log.i(TAG, "surfaceCreated, holder: " + holder);
113905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev            }
114905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
115905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev            @Override
116905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
117905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                Log.i(TAG, "surfaceChanged, holder: " + holder + ", size:" + width + "x" + height
118905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                        + ", format:" + format);
119905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
120905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                //Create dummy unobscured area to report to navigation activity.
121905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                mUnobscuredBounds = new Rect(40, 0, width - 80, height - 40);
122905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
123905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                if (mVirtualDisplay == null) {
124905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                    mVirtualDisplay = createVirtualDisplay(holder.getSurface(), width, height);
125905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                } else {
126905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                    mVirtualDisplay.setSurface(holder.getSurface());
127905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                }
128905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev            }
129905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
130905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev            @Override
131905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev            public void surfaceDestroyed(SurfaceHolder holder) {
132905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                Log.i(TAG, "surfaceDestroyed, holder: " + holder + ", detaching surface from"
133905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                        + " display, surface: " + holder.getSurface());
134905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                // detaching surface is similar to turning off the display
135905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                mVirtualDisplay.setSurface(null);
136905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev            }
137905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        });
138905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
139905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        return root;
140905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    }
141905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
142905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    private VirtualDisplay createVirtualDisplay(Surface surface, int width, int height) {
143905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        Log.i(TAG, "createVirtualDisplay, surface: " + surface + ", width: " + width
144905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                + "x" + height);
145905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        return mDisplayManager.createVirtualDisplay("Cluster-App-VD", width, height, 160, surface,
146905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
147905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    }
148905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
149905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    @Override
150905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    public void onDestroy() {
151905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        super.onDestroy();
152905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        Log.i(TAG, "onDestroy");
153905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    }
154905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
155905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    private SampleClusterServiceImpl getService() {
156905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        return ((MainClusterActivity) getActivity()).getService();
157905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    }
158905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev
159905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    private int getVirtualDisplayId() {
160905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev        return (mVirtualDisplay != null && mVirtualDisplay.getDisplay() != null)
161905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev                ? mVirtualDisplay.getDisplay().getDisplayId() : Display.INVALID_DISPLAY;
162905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev    }
163905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev}
164