content: /*
   * Copyright (C) 2007 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.app;
  
  import android.annotation.IntDef;
  import android.annotation.NonNull;
  import android.annotation.Nullable;
  import android.annotation.RequiresPermission;
  import android.annotation.SystemApi;
  import android.annotation.SystemService;
  import android.annotation.TestApi;
  import android.annotation.UnsupportedAppUsage;
  import android.content.Context;
  import android.os.Binder;
  import android.os.IBinder;
  import android.os.RemoteException;
  import android.os.ServiceManager;
  import android.util.Pair;
  import android.util.Slog;
  import android.view.View;
  
  import com.android.internal.statusbar.IStatusBarService;
  
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  
  /**
   * Allows an app to control the status bar.
   */
  @SystemService(Context.STATUS_BAR_SERVICE)
  public class StatusBarManager {
  
      /** @hide */
      public static final int DISABLE_EXPAND = View.STATUS_BAR_DISABLE_EXPAND;
      /** @hide */
      public static final int DISABLE_NOTIFICATION_ICONS = View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS;
      /** @hide */
      public static final int DISABLE_NOTIFICATION_ALERTS
              = View.STATUS_BAR_DISABLE_NOTIFICATION_ALERTS;
  
      /** @hide */
      @Deprecated
      @UnsupportedAppUsage
      public static final int DISABLE_NOTIFICATION_TICKER
              = View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER;
      /** @hide */
      public static final int DISABLE_SYSTEM_INFO = View.STATUS_BAR_DISABLE_SYSTEM_INFO;
      /** @hide */
      public static final int DISABLE_HOME = View.STATUS_BAR_DISABLE_HOME;
      /** @hide */
      public static final int DISABLE_RECENT = View.STATUS_BAR_DISABLE_RECENT;
      /** @hide */
      public static final int DISABLE_BACK = View.STATUS_BAR_DISABLE_BACK;
      /** @hide */
      public static final int DISABLE_CLOCK = View.STATUS_BAR_DISABLE_CLOCK;
      /** @hide */
      public static final int DISABLE_SEARCH = View.STATUS_BAR_DISABLE_SEARCH;
  
      /** @hide */
      @Deprecated
      public static final int DISABLE_NAVIGATION =
              View.STATUS_BAR_DISABLE_HOME | View.STATUS_BAR_DISABLE_RECENT;
  
      /** @hide */
      public static final int DISABLE_NONE = 0x00000000;
  
      /** @hide */
      public static final int DISABLE_MASK = DISABLE_EXPAND | DISABLE_NOTIFICATION_ICONS
              | DISABLE_NOTIFICATION_ALERTS | DISABLE_NOTIFICATION_TICKER
              | DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK
              | DISABLE_SEARCH;
  
      /** @hide */
      @IntDef(flag = true, prefix = {"DISABLE_"}, value = {
              DISABLE_NONE,
              DISABLE_EXPAND,
              DISABLE_NOTIFICATION_ICONS,
              DISABLE_NOTIFICATION_ALERTS,
              DISABLE_NOTIFICATION_TICKER,
              DISABLE_SYSTEM_INFO,
              DISABLE_HOME,
              DISABLE_RECENT,
              DISABLE_BACK,
              DISABLE_CLOCK,
              DISABLE_SEARCH
      })
      @Retention(RetentionPolicy.SOURCE)
      public @interface DisableFlags {}
  
      /**
       * Flag to disable quick settings.
       *
       * Setting this flag disables quick settings completely, but does not disable expanding the
       * notification shade.
       */
      /** @hide */
      public static final int DISABLE2_QUICK_SETTINGS = 1;
      /** @hide */
      public static final int DISABLE2_SYSTEM_ICONS = 1 << 1;
      /** @hide */
      public static final int DISABLE2_NOTIFICATION_SHADE = 1 << 2;
      /** @hide */
      public static final int DISABLE2_GLOBAL_ACTIONS = 1 << 3;
      /** @hide */
      public static final int DISABLE2_ROTATE_SUGGESTIONS = 1 << 4;
  
      /** @hide */
      public static final int DISABLE2_NONE = 0x00000000;
  
      /** @hide */
      public static final int DISABLE2_MASK = DISABLE2_QUICK_SETTINGS | DISABLE2_SYSTEM_ICONS
              | DISABLE2_NOTIFICATION_SHADE | DISABLE2_GLOBAL_ACTIONS | DISABLE2_ROTATE_SUGGESTIONS;
  
      /** @hide */
      @IntDef(flag = true, prefix = { "DISABLE2_" }, value = {
              DISABLE2_NONE,
              DISABLE2_MASK,
              DISABLE2_QUICK_SETTINGS,
              DISABLE2_SYSTEM_ICONS,
              DISABLE2_NOTIFICATION_SHADE,
              DISABLE2_GLOBAL_ACTIONS,
              DISABLE2_ROTATE_SUGGESTIONS
      })
      @Retention(RetentionPolicy.SOURCE)
      public @interface Disable2Flags {}
  
      /**
       * Default disable flags for setup
       *
       * @hide
       */
      public static final int DEFAULT_SETUP_DISABLE_FLAGS = DISABLE_NOTIFICATION_ALERTS
              | DISABLE_HOME | DISABLE_EXPAND | DISABLE_RECENT | DISABLE_CLOCK | DISABLE_SEARCH;
  
      /**
       * Default disable2 flags for setup
       *
       * @hide
       */
      public static final int DEFAULT_SETUP_DISABLE2_FLAGS = DISABLE2_ROTATE_SUGGESTIONS;
  
      /** @hide */
      public static final int NAVIGATION_HINT_BACK_ALT      = 1 << 0;
      /** @hide */
      public static final int NAVIGATION_HINT_IME_SHOWN     = 1 << 1;
  
      /** @hide */
      public static final int WINDOW_STATUS_BAR = 1;
      /** @hide */
      public static final int WINDOW_NAVIGATION_BAR = 2;
  
      /** @hide */
      @IntDef(flag = true, prefix = { "WINDOW_" }, value = {
          WINDOW_STATUS_BAR,
          WINDOW_NAVIGATION_BAR
      })
      @Retention(RetentionPolicy.SOURCE)
      public @interface WindowType {}
  
      /** @hide */
      public static final int WINDOW_STATE_SHOWING = 0;
      /** @hide */
      public static final int WINDOW_STATE_HIDING = 1;
      /** @hide */
      public static final int WINDOW_STATE_HIDDEN = 2;
  
      /** @hide */
      @IntDef(flag = true, prefix = { "WINDOW_STATE_" }, value = {
              WINDOW_STATE_SHOWING,
              WINDOW_STATE_HIDING,
              WINDOW_STATE_HIDDEN
      })
      @Retention(RetentionPolicy.SOURCE)
      public @interface WindowVisibleState {}
  
      /** @hide */
      public static final int CAMERA_LAUNCH_SOURCE_WIGGLE = 0;
      /** @hide */
      public static final int CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = 1;
      /** @hide */
      public static final int CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER = 2;
  
      @UnsupportedAppUsage
      private Context mContext;
      private IStatusBarService mService;
      @UnsupportedAppUsage
      private IBinder mToken = new Binder();
  
      @UnsupportedAppUsage
      StatusBarManager(Context context) {
          mContext = context;
      }
  
      @UnsupportedAppUsage
      private synchronized IStatusBarService getService() {
          if (mService == null) {
              mService = IStatusBarService.Stub.asInterface(
                      ServiceManager.getService(Context.STATUS_BAR_SERVICE));
              if (mService == null) {
                  Slog.w("StatusBarManager", "warning: no STATUS_BAR_SERVICE");
              }
          }
          return mService;
      }
  
      /**
       * Disable some features in the status bar.  Pass the bitwise-or of the DISABLE_* flags.
       * To re-enable everything, pass {@link #DISABLE_NONE}.
       *
       * @hide
       */
      @UnsupportedAppUsage
      public void disable(int what) {
          try {
              final int userId = Binder.getCallingUserHandle().getIdentifier();
              final IStatusBarService svc = getService();
              if (svc != null) {
                  svc.disableForUser(what, mToken, mContext.getPackageName(), userId);
              }
          } catch (RemoteException ex) {
              throw ex.rethrowFromSystemServer();
          }
      }
  
      /**
       * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags.
       * To re-enable everything, pass {@link #DISABLE_NONE}.
       *
       * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags.
       *
       * @hide
       */
      public void disable2(@Disable2Flags int what) {
          try {
              final int userId = Binder.getCallingUserHandle().getIdentifier();
              final IStatusBarService svc = getService();
              if (svc != null) {
                  svc.disable2ForUser(what, mToken, mContext.getPackageName(), userId);
              }
          } catch (RemoteException ex) {
              throw ex.rethrowFromSystemServer();
          }
      }
  
      /**
       * Expand the notifications panel.
       *
       * @hide
       */
      @UnsupportedAppUsage
      public void expandNotificationsPanel() {
          try {
              final IStatusBarService svc = getService();
              if (svc != null) {
                  svc.expandNotificationsPanel();
              }
          } catch (RemoteException ex) {
              throw ex.rethrowFromSystemServer();
          }
      }
  
      /**
       * Collapse the notifications and settings panels.
       *
       * @hide
       */
      @UnsupportedAppUsage
      public void collapsePanels() {
          try {
              final IStatusBarService svc = getService();
              if (svc != null) {
                  svc.collapsePanels();
              }
          } catch (RemoteException ex) {
              throw ex.rethrowFromSystemServer();
          }
      }
  
      /**
       * Expand the settings panel.
       *
       * @hide
       */
      @UnsupportedAppUsage
      public void expandSettingsPanel() {
          expandSettingsPanel(null);
      }
  
      /**
       * Expand the settings panel and open a subPanel. If the subpanel is null or does not have a
       * corresponding tile, the QS panel is simply expanded
       *
       * @hide
       */
      @UnsupportedAppUsage
      public void expandSettingsPanel(@Nullable String subPanel) {
          try {
              final IStatusBarService svc = getService();
              if (svc != null) {
                  svc.expandSettingsPanel(subPanel);
              }
          } catch (RemoteException ex) {
              throw ex.rethrowFromSystemServer();
          }
      }
  
      /** @hide */
      @UnsupportedAppUsage
      public void setIcon(String slot, int iconId, int iconLevel, String contentDescription) {
          try {
              final IStatusBarService svc = getService();
              if (svc != null) {
                  svc.setIcon(slot, mContext.getPackageName(), iconId, iconLevel,
                      contentDescription);
              }
          } catch (RemoteException ex) {
              throw ex.rethrowFromSystemServer();
          }
      }
  
      /** @hide */
      @UnsupportedAppUsage
      public void removeIcon(String slot) {
          try {
              final IStatusBarService svc = getService();
              if (svc != null) {
                  svc.removeIcon(slot);
              }
          } catch (RemoteException ex) {
              throw ex.rethrowFromSystemServer();
          }
      }
  
      /** @hide */
      @UnsupportedAppUsage
      public void setIconVisibility(String slot, boolean visible) {
          try {
              final IStatusBarService svc = getService();
              if (svc != null) {
                  svc.setIconVisibility(slot, visible);
              }
          } catch (RemoteException ex) {
              throw ex.rethrowFromSystemServer();
          }
      }
  
      /**
       * Enable or disable status bar elements (notifications, clock) which are inappropriate during
       * device setup.
       *
       * @param disabled whether to apply or remove the disabled flags
       *
       * @hide
       */
      @SystemApi
      @TestApi
      @RequiresPermission(android.Manifest.permission.STATUS_BAR)
      public void setDisabledForSetup(boolean disabled) {
          try {
              final int userId = Binder.getCallingUserHandle().getIdentifier();
              final IStatusBarService svc = getService();
              if (svc != null) {
                  svc.disableForUser(disabled ? DEFAULT_SETUP_DISABLE_FLAGS : DISABLE_NONE,
                          mToken, mContext.getPackageName(), userId);
                  svc.disable2ForUser(disabled ? DEFAULT_SETUP_DISABLE2_FLAGS : DISABLE2_NONE,
                          mToken, mContext.getPackageName(), userId);
              }
          } catch (RemoteException ex) {
              throw ex.rethrowFromSystemServer();
          }
      }
  
      /**
       * Get this app's currently requested disabled components
       *
       * @return a new DisableInfo
       *
       * @hide
       */
      @SystemApi
      @TestApi
      @RequiresPermission(android.Manifest.permission.STATUS_BAR)
      @NonNull
      public DisableInfo getDisableInfo() {
          try {
              final int userId = Binder.getCallingUserHandle().getIdentifier();
              final IStatusBarService svc = getService();
              int[] flags = new int[] {0, 0};
              if (svc != null) {
                  flags = svc.getDisableFlags(mToken, userId);
              }
  
              return new DisableInfo(flags[0], flags[1]);
          } catch (RemoteException ex) {
              throw ex.rethrowFromSystemServer();
          }
      }
  
      /** @hide */
      public static String windowStateToString(int state) {
          if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING";
          if (state == WINDOW_STATE_HIDDEN) return "WINDOW_STATE_HIDDEN";
          if (state == WINDOW_STATE_SHOWING) return "WINDOW_STATE_SHOWING";
          return "WINDOW_STATE_UNKNOWN";
      }
  
      /**
       * DisableInfo describes this app's requested state of the StatusBar with regards to which
       * components are enabled/disabled
       *
       * @hide
       */
      @SystemApi
      @TestApi
      public static final class DisableInfo {
  
          private boolean mStatusBarExpansion;
          private boolean mNavigateHome;
          private boolean mNotificationPeeking;
          private boolean mRecents;
          private boolean mSearch;
          private boolean mSystemIcons;
          private boolean mClock;
          private boolean mNotificationIcons;
  
          /** @hide */
          public DisableInfo(int flags1, int flags2) {
              mStatusBarExpansion = (flags1 & DISABLE_EXPAND) != 0;
              mNavigateHome = (flags1 & DISABLE_HOME) != 0;
              mNotificationPeeking = (flags1 & DISABLE_NOTIFICATION_ALERTS) != 0;
              mRecents = (flags1 & DISABLE_RECENT) != 0;
              mSearch = (flags1 & DISABLE_SEARCH) != 0;
              mSystemIcons = (flags1 & DISABLE_SYSTEM_INFO) != 0;
              mClock = (flags1 & DISABLE_CLOCK) != 0;
              mNotificationIcons = (flags1 & DISABLE_NOTIFICATION_ICONS) != 0;
          }
  
          /** @hide */
          public DisableInfo() {}
  
          /**
           * @return {@code true} if expanding the notification shade is disabled
           *
           * @hide
           */
          @SystemApi
          @TestApi
          public boolean isStatusBarExpansionDisabled() {
              return mStatusBarExpansion;
          }
  
          /** * @hide */
          public void setStatusBarExpansionDisabled(boolean disabled) {
              mStatusBarExpansion = disabled;
          }
  
          /**
           * @return {@code true} if navigation home is disabled
           *
           * @hide
           */
          @SystemApi
          @TestApi
          public boolean isNavigateToHomeDisabled() {
              return mNavigateHome;
          }
  
          /** * @hide */
          public void setNagivationHomeDisabled(boolean disabled) {
              mNavigateHome = disabled;
          }
  
          /**
           * @return {@code true} if notification peeking (heads-up notification) is disabled
           *
           * @hide
           */
          @SystemApi
          @TestApi
          public boolean isNotificationPeekingDisabled() {
              return mNotificationPeeking;
          }
  
          /** @hide */
          public void setNotificationPeekingDisabled(boolean disabled) {
              mNotificationPeeking = disabled;
          }
  
          /**
           * @return {@code true} if mRecents/overview is disabled
           *
           * @hide
           */
          @SystemApi
          @TestApi
          public boolean isRecentsDisabled() {
              return mRecents;
          }
  
          /**  @hide */
          public void setRecentsDisabled(boolean disabled) {
              mRecents = disabled;
          }
  
          /**
           * @return {@code true} if mSearch is disabled
           *
           * @hide
           */
          @SystemApi
          @TestApi
          public boolean isSearchDisabled() {
              return mSearch;
          }
  
          /** @hide */
          public void setSearchDisabled(boolean disabled) {
              mSearch = disabled;
          }
  
          /**
           * @return {@code true} if system icons are disabled
           *
           * @hide
           */
          public boolean areSystemIconsDisabled() {
              return mSystemIcons;
          }
  
          /** * @hide */
          public void setSystemIconsDisabled(boolean disabled) {
              mSystemIcons = disabled;
          }
  
          /**
           * @return {@code true} if the clock icon is disabled
           *
           * @hide
           */
          public boolean isClockDisabled() {
              return mClock;
          }
  
          /** * @hide */
          public void setClockDisabled(boolean disabled) {
              mClock = disabled;
          }
  
          /**
           * @return {@code true} if notification icons are disabled
           *
           * @hide
           */
          public boolean areNotificationIconsDisabled() {
              return mNotificationIcons;
          }
  
          /** * @hide */
          public void setNotificationIconsDisabled(boolean disabled) {
              mNotificationIcons = disabled;
          }
  
          /**
           * @return {@code true} if no components are disabled (default state)
           *
           * @hide
           */
          @SystemApi
          @TestApi
          public boolean areAllComponentsEnabled() {
              return !mStatusBarExpansion && !mNavigateHome && !mNotificationPeeking && !mRecents
                      && !mSearch && !mSystemIcons && !mClock && !mNotificationIcons;
          }
  
          /** @hide */
          public void setEnableAll() {
              mStatusBarExpansion = false;
              mNavigateHome = false;
              mNotificationPeeking = false;
              mRecents = false;
              mSearch = false;
              mSystemIcons = false;
              mClock = false;
              mNotificationIcons = false;
          }
  
          /**
           * @return {@code true} if all status bar components are disabled
           *
           * @hide
           */
          public boolean areAllComponentsDisabled() {
              return mStatusBarExpansion && mNavigateHome && mNotificationPeeking
                      && mRecents && mSearch && mSystemIcons && mClock && mNotificationIcons;
          }
  
          /** @hide */
          public void setDisableAll() {
              mStatusBarExpansion = true;
              mNavigateHome = true;
              mNotificationPeeking = true;
              mRecents = true;
              mSearch = true;
              mSystemIcons = true;
              mClock = true;
              mNotificationIcons = true;
          }
  
          @Override
          public String toString() {
              StringBuilder sb = new StringBuilder();
              sb.append("DisableInfo: ");
              sb.append(" mStatusBarExpansion=").append(mStatusBarExpansion ? "disabled" : "enabled");
              sb.append(" mNavigateHome=").append(mNavigateHome ? "disabled" : "enabled");
              sb.append(" mNotificationPeeking=")
                      .append(mNotificationPeeking ? "disabled" : "enabled");
              sb.append(" mRecents=").append(mRecents ? "disabled" : "enabled");
              sb.append(" mSearch=").append(mSearch ? "disabled" : "enabled");
              sb.append(" mSystemIcons=").append(mSystemIcons ? "disabled" : "enabled");
              sb.append(" mClock=").append(mClock ? "disabled" : "enabled");
              sb.append(" mNotificationIcons=").append(mNotificationIcons ? "disabled" : "enabled");
  
              return sb.toString();
  
          }
  
          /**
           * Convert a DisableInfo to equivalent flags
           * @return a pair of equivalent disable flags
           *
           * @hide
           */
          public Pair<Integer, Integer> toFlags() {
              int disable1 = DISABLE_NONE;
              int disable2 = DISABLE2_NONE;
  
              if (mStatusBarExpansion) disable1 |= DISABLE_EXPAND;
              if (mNavigateHome) disable1 |= DISABLE_HOME;
              if (mNotificationPeeking) disable1 |= DISABLE_NOTIFICATION_ALERTS;
              if (mRecents) disable1 |= DISABLE_RECENT;
              if (mSearch) disable1 |= DISABLE_SEARCH;
              if (mSystemIcons) disable1 |= DISABLE_SYSTEM_INFO;
              if (mClock) disable1 |= DISABLE_CLOCK;
              if (mNotificationIcons) disable1 |= DISABLE_NOTIFICATION_ICONS;
  
              return new Pair<Integer, Integer>(disable1, disable2);
          }
      }
  }
  