• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 com.google.android.car.multidisplaytest.present;
18 
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.app.Presentation;
22 import android.content.Context;
23 import android.content.DialogInterface;
24 import android.content.res.Resources;
25 import android.graphics.Color;
26 import android.hardware.display.DisplayManager;
27 import android.os.Bundle;
28 import android.os.Parcel;
29 import android.os.Parcelable;
30 import android.os.Parcelable.Creator;
31 import android.util.Log;
32 import android.util.SparseArray;
33 import android.view.Display;
34 import android.view.LayoutInflater;
35 import android.view.View;
36 import android.view.ViewGroup;
37 import android.view.WindowManager;
38 import android.widget.ArrayAdapter;
39 import android.widget.Button;
40 import android.widget.CheckBox;
41 import android.widget.CompoundButton;
42 import android.widget.ImageView;
43 import android.widget.ListView;
44 import android.widget.TextView;
45 
46 import androidx.fragment.app.Fragment;
47 
48 import com.google.android.car.multidisplaytest.R;
49 
50 import java.util.Arrays;
51 
52 /**
53  * Modified from
54  * //development/samples/ApiDemos/src/com/example/android/apis/app/PresentationActivity.java
55  * Show content on selected displays with Presentation and DisplayManager APIs
56  */
57 public class PresentTestFragment extends Fragment {
58     private static final String TAG = PresentTestFragment.class.getSimpleName();
59     private static final int[] PHOTOS = new int[] {
60         R.drawable.photo_landscape, R.drawable.photo_portrait
61     };
62     private Display mCurrentDisplay;
63     private DisplayManager mDisplayManager;
64     private DisplayListAdapter mDisplayListAdapter;
65     private CheckBox mShowAllDisplaysCheckbox;
66     private ListView mListView;
67     private int mNextImageNumber;
68 
69     // This state persist to restore the old presentation
70     private SparseArray<DemoPresentationContents> mSavedPresentationContents;
71     // List of all currently visible presentations indexed by display id.
72     private final SparseArray<DemoPresentation> mActivePresentations =
73             new SparseArray<DemoPresentation>();
74 
75     // Listens for displays to be added, changed or removed.
76     private DisplayManager.DisplayListener mDisplayListener;
77     // Listens for when presentations are dismissed.
78     private DialogInterface.OnDismissListener mOnDismissListener;
79     // Listens for Info button clicked.
80     private View.OnClickListener mOnClickListener;
81     // Listens for checked Display changed.
82     private CompoundButton.OnCheckedChangeListener mOnCheckedChangedListener;
83 
84     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)85     public View onCreateView(LayoutInflater inflater, ViewGroup container,
86             Bundle savedInstanceState) {
87         View view = inflater.inflate(R.layout.presentation_fragment, container, false);
88         mSavedPresentationContents = new SparseArray<DemoPresentationContents>();
89         // Get the display manager service.
90         mDisplayManager = (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
91         mCurrentDisplay = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE))
92             .getDefaultDisplay();
93 
94         setupListeners(view);
95 
96         mShowAllDisplaysCheckbox = view.findViewById(R.id.show_all_displays);
97         mShowAllDisplaysCheckbox.setOnCheckedChangeListener(mOnCheckedChangedListener);
98 
99         mDisplayListAdapter = new DisplayListAdapter(getContext());
100 
101         mListView = view.findViewById(R.id.display_list);
102         mListView.setAdapter(mDisplayListAdapter);
103 
104         return view;
105     }
106 
setupListeners(View view)107     private void setupListeners(View view) {
108         mDisplayListener = new DisplayManager.DisplayListener() {
109             @Override
110             public void onDisplayAdded(int displayId) {
111                 Log.d(TAG, "Display #" + displayId + " added.");
112                 mDisplayListAdapter.updateShownDisplays();
113             }
114 
115             @Override
116             public void onDisplayChanged(int displayId) {
117                 Log.d(TAG, "Display #" + displayId + " changed.");
118                 mDisplayListAdapter.updateShownDisplays();
119             }
120 
121             @Override
122             public void onDisplayRemoved(int displayId) {
123                 Log.d(TAG, "Display #" + displayId + " removed.");
124                 mDisplayListAdapter.updateShownDisplays();
125             }
126         };
127 
128         mOnDismissListener = new DialogInterface.OnDismissListener() {
129             @Override
130             public void onDismiss(DialogInterface dialog) {
131                 DemoPresentation presentation = (DemoPresentation) dialog;
132                 int displayId = presentation.getDisplay().getDisplayId();
133                 Log.d(TAG, "Presentation on display #" + displayId + " was dismissed.");
134                 mActivePresentations.delete(displayId);
135                 mDisplayListAdapter.notifyDataSetChanged();
136             }
137         };
138 
139         mOnClickListener = new View.OnClickListener() {
140             @Override
141             public void onClick(View v) {
142                 Context context = v.getContext();
143                 AlertDialog.Builder builder = new AlertDialog.Builder(context);
144                 final Display display = (Display) v.getTag();
145                 Resources r = context.getResources();
146                 AlertDialog alert = builder
147                         .setTitle(r.getString(
148                             R.string.presentation_alert_info_text, display.getDisplayId()))
149                         .setMessage(display.toString())
150                         .setNeutralButton(R.string.presentation_alert_dismiss_text,
151                             (dialog, which) -> dialog.dismiss())
152                         .create();
153                 alert.show();
154             }
155         };
156 
157         mOnCheckedChangedListener = new CompoundButton.OnCheckedChangeListener(){
158             @Override
159             public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
160                 if (buttonView == mShowAllDisplaysCheckbox) {
161                     // Show all displays checkbox was toggled.
162                     mDisplayListAdapter.updateShownDisplays();
163                 } else {
164                     // Display item checkbox was toggled.
165                     final Display display = (Display) buttonView.getTag();
166                     if (isChecked) {
167                         DemoPresentationContents contents =
168                                 new DemoPresentationContents(getNextPhoto());
169                         showPresentation(display, contents);
170                     } else {
171                         hidePresentation(display);
172                     }
173                     mDisplayListAdapter.updateShownDisplays();
174                 }
175             }
176         };
177     }
178 
179     @Override
onResume()180     public void onResume() {
181         super.onResume();
182         mDisplayListAdapter.updateShownDisplays();
183         mSavedPresentationContents.clear();
184 
185         // Register to receive events from the display manager.
186         mDisplayManager.registerDisplayListener(mDisplayListener, null);
187     }
188 
189     @Override
onPause()190     public void onPause() {
191         super.onPause();
192         mDisplayManager.unregisterDisplayListener(mDisplayListener);
193         Log.d(TAG, "Activity is being paused. Dismissing all active presentation.");
194 
195         for (int i = 0; i < mActivePresentations.size(); i++) {
196             DemoPresentation presentation = mActivePresentations.valueAt(i);
197             presentation.dismiss();
198         }
199         mActivePresentations.clear();
200     }
201 
202     /**
203      * Shows a Presentation on the specified display.
204      */
showPresentation(Display display, DemoPresentationContents contents)205     private void showPresentation(Display display, DemoPresentationContents contents) {
206         final int displayId = display.getDisplayId();
207         if (mActivePresentations.get(displayId) != null) {
208             Log.w(TAG, "Active presentation exists on Display #" + displayId + ".");
209             return;
210         }
211 
212         Log.d(TAG, "Showing presentation photo #" + contents.mPhoto
213                 + " on display #" + displayId + ".");
214 
215         DemoPresentation presentation = new DemoPresentation(getContext(), display, contents);
216         presentation.show();
217         presentation.setOnDismissListener(mOnDismissListener);
218         mActivePresentations.put(displayId, presentation);
219     }
220 
221     /**
222      * Hides a Presentation on the specified display.
223      */
hidePresentation(Display display)224     private void hidePresentation(Display display) {
225         final int displayId = display.getDisplayId();
226         DemoPresentation presentation = mActivePresentations.get(displayId);
227         if (presentation == null) {
228             return;
229         }
230 
231         Log.d(TAG, "Dismissing presentation on display #" + displayId + ".");
232 
233         presentation.dismiss();
234         mActivePresentations.delete(displayId);
235     }
236 
getNextPhoto()237     private int getNextPhoto() {
238         final int photo = mNextImageNumber;
239         mNextImageNumber = (mNextImageNumber + 1) % PHOTOS.length;
240         return photo;
241     }
242 
243     private final class DisplayListAdapter extends ArrayAdapter<Display> {
244         private final Activity mActivity;
245         private final Context mContext;
246         private Display[] mShownDisplays;
247 
DisplayListAdapter(Context context)248         DisplayListAdapter(Context context) {
249             super(context, R.layout.presentation_list_item);
250             mActivity = (Activity) context;
251             mContext = context;
252             mShownDisplays = new Display[] {mCurrentDisplay};
253         }
254 
255         @Override
getView(int position, View convertView, ViewGroup parent)256         public View getView(int position, View convertView, ViewGroup parent) {
257             final View view;
258             if (convertView == null) {
259                 view = ((Activity) mContext).getLayoutInflater().inflate(
260                     R.layout.presentation_list_item, null);
261             } else {
262                 view = convertView;
263             }
264             final Display display = getItem(position);
265             final int displayId = display.getDisplayId();
266 
267             DemoPresentation presentation = mActivePresentations.get(displayId);
268             DemoPresentationContents contents = presentation != null
269                     ? presentation.mContents : null;
270 
271             CheckBox cb = view.findViewById(R.id.checkbox_presentation);
272             cb.setTag(display);
273             cb.setOnCheckedChangeListener(mOnCheckedChangedListener);
274             cb.setChecked(contents != null);
275 
276             TextView tv = (TextView) view.findViewById(R.id.display_id);
277             tv.setText(view.getContext().getResources().getString(
278                     R.string.presentation_display_id_text, displayId, display.getName()));
279 
280             if (displayId == mCurrentDisplay.getDisplayId()) {
281                 tv.append(" [Current display]");
282                 cb.setEnabled(false);
283             } else {
284                 cb.setEnabled(true);
285             }
286 
287             Button b = (Button) view.findViewById(R.id.info);
288             b.setTag(display);
289             b.setOnClickListener(mOnClickListener);
290 
291             return view;
292         }
293 
updateShownDisplays()294         public void updateShownDisplays() {
295             clear();
296 
297             String displayCategory = getDisplayCategory();
298             Display[] displays = mDisplayManager.getDisplays(displayCategory);
299             addAll(displays);
300 
301             Log.d(TAG, Arrays.toString(displays));
302         }
303 
getDisplayCategory()304         private String getDisplayCategory() {
305             return mShowAllDisplaysCheckbox.isChecked() ? null :
306                 DisplayManager.DISPLAY_CATEGORY_PRESENTATION;
307         }
308     }
309 
310     /**
311      * The presentation to show on the secondary display.
312      */
313     private static final class DemoPresentation extends Presentation {
314         private DemoPresentationContents mContents;
315 
DemoPresentation(Context context, Display display, DemoPresentationContents contents)316         DemoPresentation(Context context, Display display, DemoPresentationContents contents) {
317             super(context, display);
318             mContents = contents;
319         }
320 
321         @Override
onCreate(Bundle savedInstanceState)322         public void onCreate(Bundle savedInstanceState) {
323             super.onCreate(savedInstanceState);
324             setContentView(R.layout.presentation_content);
325 
326             Resources r = getContext().getResources();
327             ImageView image = (ImageView) findViewById(R.id.image);
328             TextView text = (TextView) findViewById(R.id.text);
329 
330             Display display = getDisplay();
331             int displayId = display.getDisplayId();
332             int photo = mContents.mPhoto;
333 
334             image.setImageDrawable(r.getDrawable(PHOTOS[photo]));
335             findViewById(android.R.id.content).setBackgroundColor(mContents.mColor);
336             text.setText(r.getString(R.string.presentation_photo_text,
337                     photo, displayId, display.getName()));
338         }
339     }
340 
341     /**
342      * Content to show in the presentation.
343      */
344     private static final class DemoPresentationContents implements Parcelable {
345         private static final int[] COLORS = {
346             Color.RED,
347             Color.GREEN,
348             Color.BLUE,
349             Color.YELLOW,
350             Color.MAGENTA,
351             Color.BLACK,
352             Color.DKGRAY
353         };
354         private int mPhoto;
355         private int mColor;
356 
357         public static final Creator<DemoPresentationContents> CREATOR =
358                 new Creator<DemoPresentationContents>() {
359                     @Override
360                     public DemoPresentationContents createFromParcel(Parcel in) {
361                         return new DemoPresentationContents(in);
362                     }
363 
364                     @Override
365                     public DemoPresentationContents[] newArray(int size) {
366                         return new DemoPresentationContents[size];
367                     }
368                 };
369 
DemoPresentationContents(int photo)370         DemoPresentationContents(int photo) {
371             this.mPhoto = photo;
372             this.mColor = COLORS[(int) (Math.random() * COLORS.length)];
373         }
374 
DemoPresentationContents(Parcel in)375         private DemoPresentationContents(Parcel in) {
376             mPhoto = in.readInt();
377             mColor = in.readInt();
378         }
379 
380         @Override
describeContents()381         public int describeContents() {
382             return 0;
383         }
384 
385         @Override
writeToParcel(Parcel dest, int flags)386         public void writeToParcel(Parcel dest, int flags) {
387             dest.writeInt(mPhoto);
388             dest.writeInt(mColor);
389         }
390     }
391 }
392