• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.android.server.display;
18 
19 import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED;
20 
21 import android.annotation.Nullable;
22 import android.content.Context;
23 import android.database.ContentObserver;
24 import android.graphics.SurfaceTexture;
25 import android.os.Handler;
26 import android.os.IBinder;
27 import android.provider.Settings;
28 import android.text.TextUtils;
29 import android.util.DisplayMetrics;
30 import android.util.Slog;
31 import android.view.Display;
32 import android.view.Gravity;
33 import android.view.Surface;
34 import android.view.SurfaceControl;
35 
36 import com.android.internal.util.DumpUtils;
37 import com.android.internal.util.IndentingPrintWriter;
38 
39 import java.io.PrintWriter;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.List;
43 import java.util.regex.Matcher;
44 import java.util.regex.Pattern;
45 
46 /**
47  * A display adapter that uses overlay windows to simulate secondary displays
48  * for development purposes.  Use Development Settings to enable one or more
49  * overlay displays.
50  * <p>
51  * This object has two different handlers (which may be the same) which must not
52  * get confused.  The main handler is used to posting messages to the display manager
53  * service as usual.  The UI handler is only used by the {@link OverlayDisplayWindow}.
54  * </p><p>
55  * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
56  * </p><p>
57  * This adapter is configured via the
58  * {@link android.provider.Settings.Global#OVERLAY_DISPLAY_DEVICES} setting. This setting should be
59  * formatted as follows:
60  * <pre>
61  * [display1];[display2];...
62  * </pre>
63  * with each display specified as:
64  * <pre>
65  * [mode1]|[mode2]|...,[flag1],[flag2],...
66  * </pre>
67  * with each mode specified as:
68  * <pre>
69  * [width]x[height]/[densityDpi]
70  * </pre>
71  * Supported flags:
72  * <ul>
73  * <li><pre>secure</pre>: creates a secure display</li>
74  * <li><pre>own_content_only</pre>: only shows this display's own content</li>
75  * <li><pre>should_show_system_decorations</pre>: supports system decorations</li>
76  * </ul>
77  * </p><p>
78  * Example:
79  * <ul>
80  * <li><code>1280x720/213</code>: make one overlay that is 1280x720 at 213dpi.</li>
81  * <li><code>1920x1080/320,secure;1280x720/213</code>: make two overlays, the first at 1080p and
82  * secure; the second at 720p.</li>
83  * <li><code>1920x1080/320|3840x2160/640</code>: make one overlay that is 1920x1080 at
84  * 213dpi by default, but can also be upscaled to 3840x2160 at 640dpi by the system if the
85  * display device allows.</li>
86  * <li>If the value is empty, then no overlay display devices are created.</li>
87  * </ul></p>
88  */
89 final class OverlayDisplayAdapter extends DisplayAdapter {
90     static final String TAG = "OverlayDisplayAdapter";
91     static final boolean DEBUG = false;
92 
93     /**
94      * When this flag is set, the overlay display is considered secure.
95      * @see DisplayDeviceInfo#FLAG_SECURE
96      */
97     private static final String OVERLAY_DISPLAY_FLAG_SECURE = "secure";
98 
99     /**
100      * When this flag is set, only show this display's own content; do not mirror the content of
101      * another display.
102      * @see DisplayDeviceInfo#FLAG_OWN_CONTENT_ONLY
103      */
104     private static final String OVERLAY_DISPLAY_FLAG_OWN_CONTENT_ONLY = "own_content_only";
105 
106     /**
107      * When this flag is set, the overlay display should support system decorations.
108      * @see DisplayDeviceInfo#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
109      */
110     private static final String OVERLAY_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS =
111             "should_show_system_decorations";
112 
113     private static final int MIN_WIDTH = 100;
114     private static final int MIN_HEIGHT = 100;
115     private static final int MAX_WIDTH = 4096;
116     private static final int MAX_HEIGHT = 4096;
117 
118     private static final String DISPLAY_SPLITTER = ";";
119     private static final String MODE_SPLITTER = "\\|";
120     private static final String FLAG_SPLITTER = ",";
121 
122     private static final Pattern DISPLAY_PATTERN = Pattern.compile("([^,]+)(,[,_a-z]+)*");
123     private static final Pattern MODE_PATTERN = Pattern.compile("(\\d+)x(\\d+)/(\\d+)");
124 
125     // Unique id prefix for overlay displays.
126     private static final String UNIQUE_ID_PREFIX = "overlay:";
127 
128     private final Handler mUiHandler;
129     private final ArrayList<OverlayDisplayHandle> mOverlays =
130             new ArrayList<OverlayDisplayHandle>();
131     private String mCurrentOverlaySetting = "";
132 
133     // Called with SyncRoot lock held.
OverlayDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, Handler uiHandler)134     public OverlayDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
135             Context context, Handler handler, Listener listener, Handler uiHandler) {
136         super(syncRoot, context, handler, listener, TAG);
137         mUiHandler = uiHandler;
138     }
139 
140     @Override
dumpLocked(PrintWriter pw)141     public void dumpLocked(PrintWriter pw) {
142         super.dumpLocked(pw);
143 
144         pw.println("mCurrentOverlaySetting=" + mCurrentOverlaySetting);
145         pw.println("mOverlays: size=" + mOverlays.size());
146         for (OverlayDisplayHandle overlay : mOverlays) {
147             overlay.dumpLocked(pw);
148         }
149     }
150 
151     @Override
registerLocked()152     public void registerLocked() {
153         super.registerLocked();
154 
155         getHandler().post(new Runnable() {
156             @Override
157             public void run() {
158                 getContext().getContentResolver().registerContentObserver(
159                         Settings.Global.getUriFor(Settings.Global.OVERLAY_DISPLAY_DEVICES),
160                         true, new ContentObserver(getHandler()) {
161                             @Override
162                             public void onChange(boolean selfChange) {
163                                 updateOverlayDisplayDevices();
164                             }
165                         });
166 
167                 updateOverlayDisplayDevices();
168             }
169         });
170     }
171 
updateOverlayDisplayDevices()172     private void updateOverlayDisplayDevices() {
173         synchronized (getSyncRoot()) {
174             updateOverlayDisplayDevicesLocked();
175         }
176     }
177 
updateOverlayDisplayDevicesLocked()178     private void updateOverlayDisplayDevicesLocked() {
179         String value = Settings.Global.getString(getContext().getContentResolver(),
180                 Settings.Global.OVERLAY_DISPLAY_DEVICES);
181         if (value == null) {
182             value = "";
183         }
184 
185         if (value.equals(mCurrentOverlaySetting)) {
186             return;
187         }
188         mCurrentOverlaySetting = value;
189 
190         if (!mOverlays.isEmpty()) {
191             Slog.i(TAG, "Dismissing all overlay display devices.");
192             for (OverlayDisplayHandle overlay : mOverlays) {
193                 overlay.dismissLocked();
194             }
195             mOverlays.clear();
196         }
197 
198         int count = 0;
199         for (String part : value.split(DISPLAY_SPLITTER)) {
200             Matcher displayMatcher = DISPLAY_PATTERN.matcher(part);
201             if (displayMatcher.matches()) {
202                 if (count >= 4) {
203                     Slog.w(TAG, "Too many overlay display devices specified: " + value);
204                     break;
205                 }
206                 String modeString = displayMatcher.group(1);
207                 String flagString = displayMatcher.group(2);
208                 ArrayList<OverlayMode> modes = new ArrayList<>();
209                 for (String mode : modeString.split(MODE_SPLITTER)) {
210                     Matcher modeMatcher = MODE_PATTERN.matcher(mode);
211                     if (modeMatcher.matches()) {
212                         try {
213                             int width = Integer.parseInt(modeMatcher.group(1), 10);
214                             int height = Integer.parseInt(modeMatcher.group(2), 10);
215                             int densityDpi = Integer.parseInt(modeMatcher.group(3), 10);
216                             if (width >= MIN_WIDTH && width <= MAX_WIDTH
217                                     && height >= MIN_HEIGHT && height <= MAX_HEIGHT
218                                     && densityDpi >= DisplayMetrics.DENSITY_LOW
219                                     && densityDpi <= DisplayMetrics.DENSITY_XXXHIGH) {
220                                 modes.add(new OverlayMode(width, height, densityDpi));
221                                 continue;
222                             } else {
223                                 Slog.w(TAG, "Ignoring out-of-range overlay display mode: " + mode);
224                             }
225                         } catch (NumberFormatException ex) {
226                         }
227                     } else if (mode.isEmpty()) {
228                         continue;
229                     }
230                 }
231                 if (!modes.isEmpty()) {
232                     int number = ++count;
233                     String name = getContext().getResources().getString(
234                             com.android.internal.R.string.display_manager_overlay_display_name,
235                             number);
236                     int gravity = chooseOverlayGravity(number);
237                     OverlayFlags flags = OverlayFlags.parseFlags(flagString);
238 
239                     Slog.i(TAG, "Showing overlay display device #" + number
240                             + ": name=" + name + ", modes=" + Arrays.toString(modes.toArray())
241                             + ", flags=" + flags);
242 
243                     mOverlays.add(new OverlayDisplayHandle(name, modes, gravity, flags, number));
244                     continue;
245                 }
246             }
247             Slog.w(TAG, "Malformed overlay display devices setting: " + value);
248         }
249     }
250 
chooseOverlayGravity(int overlayNumber)251     private static int chooseOverlayGravity(int overlayNumber) {
252         switch (overlayNumber) {
253             case 1:
254                 return Gravity.TOP | Gravity.LEFT;
255             case 2:
256                 return Gravity.BOTTOM | Gravity.RIGHT;
257             case 3:
258                 return Gravity.TOP | Gravity.RIGHT;
259             case 4:
260             default:
261                 return Gravity.BOTTOM | Gravity.LEFT;
262         }
263     }
264 
265     private abstract class OverlayDisplayDevice extends DisplayDevice {
266         private final String mName;
267         private final float mRefreshRate;
268         private final long mDisplayPresentationDeadlineNanos;
269         private final OverlayFlags mFlags;
270         private final List<OverlayMode> mRawModes;
271         private final Display.Mode[] mModes;
272         private final int mDefaultMode;
273 
274         private int mState;
275         private SurfaceTexture mSurfaceTexture;
276         private Surface mSurface;
277         private DisplayDeviceInfo mInfo;
278         private int mActiveMode;
279 
OverlayDisplayDevice(IBinder displayToken, String name, List<OverlayMode> modes, int activeMode, int defaultMode, float refreshRate, long presentationDeadlineNanos, OverlayFlags flags, int state, SurfaceTexture surfaceTexture, int number)280         OverlayDisplayDevice(IBinder displayToken, String name,
281                 List<OverlayMode> modes, int activeMode, int defaultMode,
282                 float refreshRate, long presentationDeadlineNanos,
283                 OverlayFlags flags, int state, SurfaceTexture surfaceTexture, int number) {
284             super(OverlayDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + number,
285                     getContext());
286             mName = name;
287             mRefreshRate = refreshRate;
288             mDisplayPresentationDeadlineNanos = presentationDeadlineNanos;
289             mFlags = flags;
290             mState = state;
291             mSurfaceTexture = surfaceTexture;
292             mRawModes = modes;
293             mModes = new Display.Mode[modes.size()];
294             for (int i = 0; i < modes.size(); i++) {
295                 OverlayMode mode = modes.get(i);
296                 mModes[i] = createMode(mode.mWidth, mode.mHeight, refreshRate);
297             }
298             mActiveMode = activeMode;
299             mDefaultMode = defaultMode;
300         }
301 
destroyLocked()302         public void destroyLocked() {
303             mSurfaceTexture = null;
304             if (mSurface != null) {
305                 mSurface.release();
306                 mSurface = null;
307             }
308             SurfaceControl.destroyDisplay(getDisplayTokenLocked());
309         }
310 
311         @Override
hasStableUniqueId()312         public boolean hasStableUniqueId() {
313             return false;
314         }
315 
316         @Override
performTraversalLocked(SurfaceControl.Transaction t)317         public void performTraversalLocked(SurfaceControl.Transaction t) {
318             if (mSurfaceTexture != null) {
319                 if (mSurface == null) {
320                     mSurface = new Surface(mSurfaceTexture);
321                 }
322                 setSurfaceLocked(t, mSurface);
323             }
324         }
325 
setStateLocked(int state)326         public void setStateLocked(int state) {
327             mState = state;
328             mInfo = null;
329         }
330 
331         @Override
getDisplayDeviceInfoLocked()332         public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
333             if (mInfo == null) {
334                 Display.Mode mode = mModes[mActiveMode];
335                 OverlayMode rawMode = mRawModes.get(mActiveMode);
336                 mInfo = new DisplayDeviceInfo();
337                 mInfo.name = mName;
338                 mInfo.uniqueId = getUniqueId();
339                 mInfo.width = mode.getPhysicalWidth();
340                 mInfo.height = mode.getPhysicalHeight();
341                 mInfo.modeId = mode.getModeId();
342                 mInfo.defaultModeId = mModes[0].getModeId();
343                 mInfo.supportedModes = mModes;
344                 mInfo.densityDpi = rawMode.mDensityDpi;
345                 mInfo.xDpi = rawMode.mDensityDpi;
346                 mInfo.yDpi = rawMode.mDensityDpi;
347                 mInfo.presentationDeadlineNanos = mDisplayPresentationDeadlineNanos +
348                         1000000000L / (int) mRefreshRate;   // display's deadline + 1 frame
349                 mInfo.flags = DisplayDeviceInfo.FLAG_PRESENTATION;
350                 if (mFlags.mSecure) {
351                     mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
352                 }
353                 if (mFlags.mOwnContentOnly) {
354                     mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
355                 }
356                 if (mFlags.mShouldShowSystemDecorations) {
357                     mInfo.flags |= DisplayDeviceInfo.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
358                 }
359                 mInfo.type = Display.TYPE_OVERLAY;
360                 mInfo.touch = DisplayDeviceInfo.TOUCH_VIRTUAL;
361                 mInfo.state = mState;
362                 // The display is trusted since it is created by system.
363                 mInfo.flags |= FLAG_TRUSTED;
364             }
365             return mInfo;
366         }
367 
368         @Override
setDesiredDisplayModeSpecsLocked( DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs)369         public void setDesiredDisplayModeSpecsLocked(
370                 DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs) {
371             final int id = displayModeSpecs.baseModeId;
372             int index = -1;
373             if (id == 0) {
374                 // Use the default.
375                 index = 0;
376             } else {
377                 for (int i = 0; i < mModes.length; i++) {
378                     if (mModes[i].getModeId() == id) {
379                         index = i;
380                         break;
381                     }
382                 }
383             }
384             if (index == -1) {
385                 Slog.w(TAG, "Unable to locate mode " + id + ", reverting to default.");
386                 index = mDefaultMode;
387             }
388             if (mActiveMode == index) {
389                 return;
390             }
391             mActiveMode = index;
392             mInfo = null;
393             sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
394             onModeChangedLocked(index);
395         }
396 
397         /**
398          * Called when the device switched to a new mode.
399          *
400          * @param index index of the mode in the list of modes
401          */
onModeChangedLocked(int index)402         public abstract void onModeChangedLocked(int index);
403     }
404 
405     /**
406      * Functions as a handle for overlay display devices which are created and
407      * destroyed asynchronously.
408      *
409      * Guarded by the {@link DisplayManagerService.SyncRoot} lock.
410      */
411     private final class OverlayDisplayHandle implements OverlayDisplayWindow.Listener {
412         private static final int DEFAULT_MODE_INDEX = 0;
413 
414         private final String mName;
415         private final List<OverlayMode> mModes;
416         private final int mGravity;
417         private final OverlayFlags mFlags;
418         private final int mNumber;
419 
420         private OverlayDisplayWindow mWindow;
421         private OverlayDisplayDevice mDevice;
422         private int mActiveMode;
423 
OverlayDisplayHandle( String name, List<OverlayMode> modes, int gravity, OverlayFlags flags, int number)424         OverlayDisplayHandle(
425                 String name,
426                 List<OverlayMode> modes,
427                 int gravity,
428                 OverlayFlags flags,
429                 int number) {
430             mName = name;
431             mModes = modes;
432             mGravity = gravity;
433             mFlags = flags;
434             mNumber = number;
435 
436             mActiveMode = 0;
437 
438             showLocked();
439         }
440 
showLocked()441         private void showLocked() {
442             mUiHandler.post(mShowRunnable);
443         }
444 
dismissLocked()445         public void dismissLocked() {
446             mUiHandler.removeCallbacks(mShowRunnable);
447             mUiHandler.post(mDismissRunnable);
448         }
449 
onActiveModeChangedLocked(int index)450         private void onActiveModeChangedLocked(int index) {
451             mUiHandler.removeCallbacks(mResizeRunnable);
452             mActiveMode = index;
453             if (mWindow != null) {
454                 mUiHandler.post(mResizeRunnable);
455             }
456         }
457 
458         // Called on the UI thread.
459         @Override
onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate, long presentationDeadlineNanos, int state)460         public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate,
461                 long presentationDeadlineNanos, int state) {
462             synchronized (getSyncRoot()) {
463                 IBinder displayToken = SurfaceControl.createDisplay(mName, mFlags.mSecure);
464                 mDevice = new OverlayDisplayDevice(displayToken, mName, mModes, mActiveMode,
465                         DEFAULT_MODE_INDEX, refreshRate, presentationDeadlineNanos,
466                         mFlags, state, surfaceTexture, mNumber) {
467                     @Override
468                     public void onModeChangedLocked(int index) {
469                         onActiveModeChangedLocked(index);
470                     }
471                 };
472 
473                 sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
474             }
475         }
476 
477         // Called on the UI thread.
478         @Override
onWindowDestroyed()479         public void onWindowDestroyed() {
480             synchronized (getSyncRoot()) {
481                 if (mDevice != null) {
482                     mDevice.destroyLocked();
483                     sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_REMOVED);
484                 }
485             }
486         }
487 
488         // Called on the UI thread.
489         @Override
onStateChanged(int state)490         public void onStateChanged(int state) {
491             synchronized (getSyncRoot()) {
492                 if (mDevice != null) {
493                     mDevice.setStateLocked(state);
494                     sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_CHANGED);
495                 }
496             }
497         }
498 
dumpLocked(PrintWriter pw)499         public void dumpLocked(PrintWriter pw) {
500             pw.println("  " + mName + ":");
501             pw.println("    mModes=" + Arrays.toString(mModes.toArray()));
502             pw.println("    mActiveMode=" + mActiveMode);
503             pw.println("    mGravity=" + mGravity);
504             pw.println("    mFlags=" + mFlags);
505             pw.println("    mNumber=" + mNumber);
506 
507             // Try to dump the window state.
508             if (mWindow != null) {
509                 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
510                 ipw.increaseIndent();
511                 DumpUtils.dumpAsync(mUiHandler, mWindow, ipw, "", 200);
512             }
513         }
514 
515         // Runs on the UI thread.
516         private final Runnable mShowRunnable = new Runnable() {
517             @Override
518             public void run() {
519                 OverlayMode mode = mModes.get(mActiveMode);
520                 OverlayDisplayWindow window = new OverlayDisplayWindow(getContext(),
521                         mName, mode.mWidth, mode.mHeight, mode.mDensityDpi, mGravity,
522                         mFlags.mSecure, OverlayDisplayHandle.this);
523                 window.show();
524 
525                 synchronized (getSyncRoot()) {
526                     mWindow = window;
527                 }
528             }
529         };
530 
531         // Runs on the UI thread.
532         private final Runnable mDismissRunnable = new Runnable() {
533             @Override
534             public void run() {
535                 OverlayDisplayWindow window;
536                 synchronized (getSyncRoot()) {
537                     window = mWindow;
538                     mWindow = null;
539                 }
540 
541                 if (window != null) {
542                     window.dismiss();
543                 }
544             }
545         };
546 
547         // Runs on the UI thread.
548         private final Runnable mResizeRunnable = new Runnable() {
549             @Override
550             public void run() {
551                 OverlayMode mode;
552                 OverlayDisplayWindow window;
553                 synchronized (getSyncRoot()) {
554                     if (mWindow == null) {
555                         return;
556                     }
557                     mode = mModes.get(mActiveMode);
558                     window = mWindow;
559                 }
560                 window.resize(mode.mWidth, mode.mHeight, mode.mDensityDpi);
561             }
562         };
563     }
564 
565     /**
566      * A display mode for an overlay display.
567      */
568     private static final class OverlayMode {
569         final int mWidth;
570         final int mHeight;
571         final int mDensityDpi;
572 
OverlayMode(int width, int height, int densityDpi)573         OverlayMode(int width, int height, int densityDpi) {
574             mWidth = width;
575             mHeight = height;
576             mDensityDpi = densityDpi;
577         }
578 
579         @Override
toString()580         public String toString() {
581             return new StringBuilder("{")
582                     .append("width=").append(mWidth)
583                     .append(", height=").append(mHeight)
584                     .append(", densityDpi=").append(mDensityDpi)
585                     .append("}")
586                     .toString();
587         }
588     }
589 
590     /** Represents the flags of the overlay display. */
591     private static final class OverlayFlags {
592         /** See {@link #OVERLAY_DISPLAY_FLAG_SECURE}. */
593         final boolean mSecure;
594 
595         /** See {@link #OVERLAY_DISPLAY_FLAG_OWN_CONTENT_ONLY}. */
596         final boolean mOwnContentOnly;
597 
598         /** See {@link #OVERLAY_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS}. */
599         final boolean mShouldShowSystemDecorations;
600 
OverlayFlags( boolean secure, boolean ownContentOnly, boolean shouldShowSystemDecorations)601         OverlayFlags(
602                 boolean secure,
603                 boolean ownContentOnly,
604                 boolean shouldShowSystemDecorations) {
605             mSecure = secure;
606             mOwnContentOnly = ownContentOnly;
607             mShouldShowSystemDecorations = shouldShowSystemDecorations;
608         }
609 
parseFlags(@ullable String flagString)610         static OverlayFlags parseFlags(@Nullable String flagString) {
611             if (TextUtils.isEmpty(flagString)) {
612                 return new OverlayFlags(
613                         false /* secure */,
614                         false /* ownContentOnly */,
615                         false /* shouldShowSystemDecorations */);
616             }
617 
618             boolean secure = false;
619             boolean ownContentOnly = false;
620             boolean shouldShowSystemDecorations = false;
621             for (String flag: flagString.split(FLAG_SPLITTER)) {
622                 if (OVERLAY_DISPLAY_FLAG_SECURE.equals(flag)) {
623                     secure = true;
624                 }
625                 if (OVERLAY_DISPLAY_FLAG_OWN_CONTENT_ONLY.equals(flag)) {
626                     ownContentOnly = true;
627                 }
628                 if (OVERLAY_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS.equals(flag)) {
629                     shouldShowSystemDecorations = true;
630                 }
631             }
632             return new OverlayFlags(secure, ownContentOnly, shouldShowSystemDecorations);
633         }
634 
635         @Override
toString()636         public String toString() {
637             return new StringBuilder("{")
638                     .append("secure=").append(mSecure)
639                     .append(", ownContentOnly=").append(mOwnContentOnly)
640                     .append(", shouldShowSystemDecorations=").append(mShouldShowSystemDecorations)
641                     .append("}")
642                     .toString();
643         }
644     }
645 }
646