Jason Monk | f66d377 | 2017-05-30 14:31:51 -0400 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file |
| 5 | * except in compliance with the License. You may obtain a copy of the License at |
| 6 | * |
| 7 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | * |
| 9 | * Unless required by applicable law or agreed to in writing, software distributed under the |
| 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 11 | * KIND, either express or implied. See the License for the specific language governing |
| 12 | * permissions and limitations under the License. |
| 13 | */ |
| 14 | |
| 15 | package com.android.systemui.util; |
| 16 | |
Vinit Nayak | 3f35db5 | 2019-08-08 17:31:48 -0700 | [diff] [blame] | 17 | import static android.view.Display.DEFAULT_DISPLAY; |
| 18 | |
Narayan Kamath | 9f72a1e | 2019-05-17 15:58:24 +0100 | [diff] [blame] | 19 | import android.Manifest; |
Vinit Nayak | 3f35db5 | 2019-08-08 17:31:48 -0700 | [diff] [blame] | 20 | import android.content.Context; |
Narayan Kamath | 9f72a1e | 2019-05-17 15:58:24 +0100 | [diff] [blame] | 21 | import android.content.Intent; |
| 22 | import android.content.pm.PackageManager; |
Matt Pietal | 5a19cb6 | 2019-10-30 12:31:07 -0400 | [diff] [blame] | 23 | import android.provider.Settings; |
Charles He | 6a79b0d | 2017-09-18 09:50:58 +0100 | [diff] [blame] | 24 | import android.view.View; |
| 25 | |
Vinit Nayak | 3f35db5 | 2019-08-08 17:31:48 -0700 | [diff] [blame] | 26 | import com.android.systemui.shared.system.QuickStepContract; |
Charles He | 6a79b0d | 2017-09-18 09:50:58 +0100 | [diff] [blame] | 27 | import com.android.systemui.statusbar.CommandQueue; |
| 28 | |
Jason Monk | f66d377 | 2017-05-30 14:31:51 -0400 | [diff] [blame] | 29 | import java.util.List; |
| 30 | import java.util.function.Consumer; |
| 31 | |
| 32 | public class Utils { |
| 33 | |
| 34 | /** |
| 35 | * Allows lambda iteration over a list. It is done in reverse order so it is safe |
Beverly | db2cef2 | 2018-06-15 11:04:02 -0400 | [diff] [blame] | 36 | * to add or remove items during the iteration. Skips over null items. |
Jason Monk | f66d377 | 2017-05-30 14:31:51 -0400 | [diff] [blame] | 37 | */ |
| 38 | public static <T> void safeForeach(List<T> list, Consumer<T> c) { |
| 39 | for (int i = list.size() - 1; i >= 0; i--) { |
Beverly | db2cef2 | 2018-06-15 11:04:02 -0400 | [diff] [blame] | 40 | T item = list.get(i); |
| 41 | if (item != null) { |
| 42 | c.accept(item); |
| 43 | } |
Jason Monk | f66d377 | 2017-05-30 14:31:51 -0400 | [diff] [blame] | 44 | } |
| 45 | } |
Charles He | 6a79b0d | 2017-09-18 09:50:58 +0100 | [diff] [blame] | 46 | |
| 47 | /** |
| 48 | * Sets the visibility of an UI element according to the DISABLE_* flags in |
| 49 | * {@link android.app.StatusBarManager}. |
| 50 | */ |
| 51 | public static class DisableStateTracker implements CommandQueue.Callbacks, |
| 52 | View.OnAttachStateChangeListener { |
| 53 | private final int mMask1; |
| 54 | private final int mMask2; |
Dave Mankoff | bcaca8a | 2019-10-31 18:04:08 -0400 | [diff] [blame] | 55 | private final CommandQueue mCommandQueue; |
Charles He | 6a79b0d | 2017-09-18 09:50:58 +0100 | [diff] [blame] | 56 | private View mView; |
| 57 | private boolean mDisabled; |
| 58 | |
Dave Mankoff | bcaca8a | 2019-10-31 18:04:08 -0400 | [diff] [blame] | 59 | public DisableStateTracker(int disableMask, int disable2Mask, CommandQueue commandQueue) { |
Charles He | 6a79b0d | 2017-09-18 09:50:58 +0100 | [diff] [blame] | 60 | mMask1 = disableMask; |
| 61 | mMask2 = disable2Mask; |
Dave Mankoff | bcaca8a | 2019-10-31 18:04:08 -0400 | [diff] [blame] | 62 | mCommandQueue = commandQueue; |
Charles He | 6a79b0d | 2017-09-18 09:50:58 +0100 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | @Override |
| 66 | public void onViewAttachedToWindow(View v) { |
| 67 | mView = v; |
Dave Mankoff | bcaca8a | 2019-10-31 18:04:08 -0400 | [diff] [blame] | 68 | mCommandQueue.addCallback(this); |
Charles He | 6a79b0d | 2017-09-18 09:50:58 +0100 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | @Override |
| 72 | public void onViewDetachedFromWindow(View v) { |
Dave Mankoff | bcaca8a | 2019-10-31 18:04:08 -0400 | [diff] [blame] | 73 | mCommandQueue.removeCallback(this); |
Charles He | 6a79b0d | 2017-09-18 09:50:58 +0100 | [diff] [blame] | 74 | mView = null; |
| 75 | } |
| 76 | |
| 77 | /** |
| 78 | * Sets visibility of this {@link View} given the states passed from |
Charles Chen | f3d295c | 2018-11-30 18:15:21 +0800 | [diff] [blame] | 79 | * {@link com.android.systemui.statusbar.CommandQueue.Callbacks#disable(int, int, int)}. |
Charles He | 6a79b0d | 2017-09-18 09:50:58 +0100 | [diff] [blame] | 80 | */ |
| 81 | @Override |
Charles Chen | f3d295c | 2018-11-30 18:15:21 +0800 | [diff] [blame] | 82 | public void disable(int displayId, int state1, int state2, boolean animate) { |
| 83 | if (displayId != mView.getDisplay().getDisplayId()) { |
| 84 | return; |
| 85 | } |
Charles He | 6a79b0d | 2017-09-18 09:50:58 +0100 | [diff] [blame] | 86 | final boolean disabled = ((state1 & mMask1) != 0) || ((state2 & mMask2) != 0); |
| 87 | if (disabled == mDisabled) return; |
| 88 | mDisabled = disabled; |
| 89 | mView.setVisibility(disabled ? View.GONE : View.VISIBLE); |
| 90 | } |
| 91 | |
| 92 | /** @return {@code true} if and only if this {@link View} is currently disabled */ |
| 93 | public boolean isDisabled() { |
| 94 | return mDisabled; |
| 95 | } |
| 96 | } |
Narayan Kamath | 9f72a1e | 2019-05-17 15:58:24 +0100 | [diff] [blame] | 97 | |
| 98 | |
| 99 | /** |
| 100 | * Returns {@code true} iff the package {@code packageName} is a headless remote display |
| 101 | * provider, i.e, that the package holds the privileged {@code REMOTE_DISPLAY_PROVIDER} |
| 102 | * permission and that it doesn't host a launcher icon. |
| 103 | */ |
| 104 | public static boolean isHeadlessRemoteDisplayProvider(PackageManager pm, String packageName) { |
| 105 | if (pm.checkPermission(Manifest.permission.REMOTE_DISPLAY_PROVIDER, packageName) |
| 106 | != PackageManager.PERMISSION_GRANTED) { |
| 107 | return false; |
| 108 | } |
| 109 | |
| 110 | Intent homeIntent = new Intent(Intent.ACTION_MAIN); |
| 111 | homeIntent.addCategory(Intent.CATEGORY_LAUNCHER); |
| 112 | homeIntent.setPackage(packageName); |
| 113 | |
| 114 | return pm.queryIntentActivities(homeIntent, 0).isEmpty(); |
| 115 | } |
| 116 | |
Vinit Nayak | 3f35db5 | 2019-08-08 17:31:48 -0700 | [diff] [blame] | 117 | /** |
| 118 | * Returns {@code true} if the navMode is that of |
| 119 | * {@link android.view.WindowManagerPolicyConstants#NAV_BAR_MODE_GESTURAL} AND |
| 120 | * the context is that of the default display |
| 121 | */ |
| 122 | public static boolean isGesturalModeOnDefaultDisplay(Context context, int navMode) { |
| 123 | return context.getDisplayId() == DEFAULT_DISPLAY |
| 124 | && QuickStepContract.isGesturalMode(navMode); |
| 125 | } |
| 126 | |
Matt Pietal | 5a19cb6 | 2019-10-30 12:31:07 -0400 | [diff] [blame] | 127 | /** |
| 128 | * Allow the media player to be shown in the QS area, controlled by 2 flags. |
Lucas Dupin | fbe9117ed | 2020-04-29 16:26:21 -0700 | [diff] [blame] | 129 | * Off by default, but can be disabled by setting to 0 |
Matt Pietal | 5a19cb6 | 2019-10-30 12:31:07 -0400 | [diff] [blame] | 130 | */ |
| 131 | public static boolean useQsMediaPlayer(Context context) { |
Lucas Dupin | fbe9117ed | 2020-04-29 16:26:21 -0700 | [diff] [blame] | 132 | int flag = Settings.Global.getInt(context.getContentResolver(), |
Lucas Dupin | 03859d7 | 2020-05-12 12:27:47 -0700 | [diff] [blame] | 133 | Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 1); |
Matt Pietal | 5a19cb6 | 2019-10-30 12:31:07 -0400 | [diff] [blame] | 134 | return flag > 0; |
| 135 | } |
Jason Monk | f66d377 | 2017-05-30 14:31:51 -0400 | [diff] [blame] | 136 | } |