content: /*
   * Copyright (C) 2006 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.CallSuper;
  import android.annotation.NonNull;
  import android.annotation.Nullable;
  import android.annotation.UnsupportedAppUsage;
  import android.content.ComponentCallbacks;
  import android.content.ComponentCallbacks2;
  import android.content.Context;
  import android.content.ContextWrapper;
  import android.content.Intent;
  import android.content.res.Configuration;
  import android.os.Bundle;
  import android.util.Log;
  import android.view.autofill.AutofillManager;
  
  import java.util.ArrayList;
  
  /**
   * Base class for maintaining global application state. You can provide your own
   * implementation by creating a subclass and specifying the fully-qualified name
   * of this subclass as the <code>"android:name"</code> attribute in your
   * AndroidManifest.xml's <code>&lt;application&gt;</code> tag. The Application
   * class, or your subclass of the Application class, is instantiated before any
   * other class when the process for your application/package is created.
   *
   * <p class="note"><strong>Note: </strong>There is normally no need to subclass
   * Application.  In most situations, static singletons can provide the same
   * functionality in a more modular way.  If your singleton needs a global
   * context (for example to register broadcast receivers), include
   * {@link android.content.Context#getApplicationContext() Context.getApplicationContext()}
   * as a {@link android.content.Context} argument when invoking your singleton's
   * <code>getInstance()</code> method.
   * </p>
   */
  public class Application extends ContextWrapper implements ComponentCallbacks2 {
      private static final String TAG = "Application";
      @UnsupportedAppUsage
      private ArrayList<ComponentCallbacks> mComponentCallbacks =
              new ArrayList<ComponentCallbacks>();
      @UnsupportedAppUsage
      private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
              new ArrayList<ActivityLifecycleCallbacks>();
      @UnsupportedAppUsage
      private ArrayList<OnProvideAssistDataListener> mAssistCallbacks = null;
  
      /** @hide */
      @UnsupportedAppUsage
      public LoadedApk mLoadedApk;
  
      public interface ActivityLifecycleCallbacks {
  
          /**
           * Called as the first step of the Activity being created. This is always called before
           * {@link Activity#onCreate}.
           */
          default void onActivityPreCreated(@NonNull Activity activity,
                  @Nullable Bundle savedInstanceState) {
          }
  
          /**
           * Called when the Activity calls {@link Activity#onCreate super.onCreate()}.
           */
          void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState);
  
          /**
           * Called as the last step of the Activity being created. This is always called after
           * {@link Activity#onCreate}.
           */
          default void onActivityPostCreated(@NonNull Activity activity,
                  @Nullable Bundle savedInstanceState) {
          }
  
          /**
           * Called as the first step of the Activity being started. This is always called before
           * {@link Activity#onStart}.
           */
          default void onActivityPreStarted(@NonNull Activity activity) {
          }
  
          /**
           * Called when the Activity calls {@link Activity#onStart super.onStart()}.
           */
          void onActivityStarted(@NonNull Activity activity);
  
          /**
           * Called as the last step of the Activity being started. This is always called after
           * {@link Activity#onStart}.
           */
          default void onActivityPostStarted(@NonNull Activity activity) {
          }
  
          /**
           * Called as the first step of the Activity being resumed. This is always called before
           * {@link Activity#onResume}.
           */
          default void onActivityPreResumed(@NonNull Activity activity) {
          }
  
          /**
           * Called when the Activity calls {@link Activity#onResume super.onResume()}.
           */
          void onActivityResumed(@NonNull Activity activity);
  
          /**
           * Called as the last step of the Activity being resumed. This is always called after
           * {@link Activity#onResume} and {@link Activity#onPostResume}.
           */
          default void onActivityPostResumed(@NonNull Activity activity) {
          }
  
          /**
           * Called as the first step of the Activity being paused. This is always called before
           * {@link Activity#onPause}.
           */
          default void onActivityPrePaused(@NonNull Activity activity) {
          }
  
          /**
           * Called when the Activity calls {@link Activity#onPause super.onPause()}.
           */
          void onActivityPaused(@NonNull Activity activity);
  
          /**
           * Called as the last step of the Activity being paused. This is always called after
           * {@link Activity#onPause}.
           */
          default void onActivityPostPaused(@NonNull Activity activity) {
          }
  
          /**
           * Called as the first step of the Activity being stopped. This is always called before
           * {@link Activity#onStop}.
           */
          default void onActivityPreStopped(@NonNull Activity activity) {
          }
  
          /**
           * Called when the Activity calls {@link Activity#onStop super.onStop()}.
           */
          void onActivityStopped(@NonNull Activity activity);
  
          /**
           * Called as the last step of the Activity being stopped. This is always called after
           * {@link Activity#onStop}.
           */
          default void onActivityPostStopped(@NonNull Activity activity) {
          }
  
          /**
           * Called as the first step of the Activity saving its instance state. This is always
           * called before {@link Activity#onSaveInstanceState}.
           */
          default void onActivityPreSaveInstanceState(@NonNull Activity activity,
                  @NonNull Bundle outState) {
          }
  
          /**
           * Called when the Activity calls
           * {@link Activity#onSaveInstanceState super.onSaveInstanceState()}.
           */
          void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState);
  
          /**
           * Called as the last step of the Activity saving its instance state. This is always
           * called after{@link Activity#onSaveInstanceState}.
           */
          default void onActivityPostSaveInstanceState(@NonNull Activity activity,
                  @NonNull Bundle outState) {
          }
  
          /**
           * Called as the first step of the Activity being destroyed. This is always called before
           * {@link Activity#onDestroy}.
           */
          default void onActivityPreDestroyed(@NonNull Activity activity) {
          }
  
          /**
           * Called when the Activity calls {@link Activity#onDestroy super.onDestroy()}.
           */
          void onActivityDestroyed(@NonNull Activity activity);
  
          /**
           * Called as the last step of the Activity being destroyed. This is always called after
           * {@link Activity#onDestroy}.
           */
          default void onActivityPostDestroyed(@NonNull Activity activity) {
          }
      }
  
      /**
       * Callback interface for use with {@link Application#registerOnProvideAssistDataListener}
       * and {@link Application#unregisterOnProvideAssistDataListener}.
       */
      public interface OnProvideAssistDataListener {
          /**
           * This is called when the user is requesting an assist, to build a full
           * {@link Intent#ACTION_ASSIST} Intent with all of the context of the current
           * application.  You can override this method to place into the bundle anything
           * you would like to appear in the {@link Intent#EXTRA_ASSIST_CONTEXT} part
           * of the assist Intent.
           */
          public void onProvideAssistData(Activity activity, Bundle data);
      }
  
      public Application() {
          super(null);
      }
  
      /**
       * Called when the application is starting, before any activity, service,
       * or receiver objects (excluding content providers) have been created.
       *
       * <p>Implementations should be as quick as possible (for example using
       * lazy initialization of state) since the time spent in this function
       * directly impacts the performance of starting the first activity,
       * service, or receiver in a process.</p>
       *
       * <p>If you override this method, be sure to call {@code super.onCreate()}.</p>
       *
       * <p class="note">Be aware that direct boot may also affect callback order on
       * Android {@link android.os.Build.VERSION_CODES#N} and later devices.
       * Until the user unlocks the device, only direct boot aware components are
       * allowed to run. You should consider that all direct boot unaware
       * components, including such {@link android.content.ContentProvider}, are
       * disabled until user unlock happens, especially when component callback
       * order matters.</p>
       */
      @CallSuper
      public void onCreate() {
      }
  
      /**
       * This method is for use in emulated process environments.  It will
       * never be called on a production Android device, where processes are
       * removed by simply killing them; no user code (including this callback)
       * is executed when doing so.
       */
      @CallSuper
      public void onTerminate() {
      }
  
      @CallSuper
      public void onConfigurationChanged(@NonNull Configuration newConfig) {
          Object[] callbacks = collectComponentCallbacks();
          if (callbacks != null) {
              for (int i=0; i<callbacks.length; i++) {
                  ((ComponentCallbacks)callbacks[i]).onConfigurationChanged(newConfig);
              }
          }
      }
  
      @CallSuper
      public void onLowMemory() {
          Object[] callbacks = collectComponentCallbacks();
          if (callbacks != null) {
              for (int i=0; i<callbacks.length; i++) {
                  ((ComponentCallbacks)callbacks[i]).onLowMemory();
              }
          }
      }
  
      @CallSuper
      public void onTrimMemory(int level) {
          Object[] callbacks = collectComponentCallbacks();
          if (callbacks != null) {
              for (int i=0; i<callbacks.length; i++) {
                  Object c = callbacks[i];
                  if (c instanceof ComponentCallbacks2) {
                      ((ComponentCallbacks2)c).onTrimMemory(level);
                  }
              }
          }
      }
  
      public void registerComponentCallbacks(ComponentCallbacks callback) {
          synchronized (mComponentCallbacks) {
              mComponentCallbacks.add(callback);
          }
      }
  
      public void unregisterComponentCallbacks(ComponentCallbacks callback) {
          synchronized (mComponentCallbacks) {
              mComponentCallbacks.remove(callback);
          }
      }
  
      public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
          synchronized (mActivityLifecycleCallbacks) {
              mActivityLifecycleCallbacks.add(callback);
          }
      }
  
      public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
          synchronized (mActivityLifecycleCallbacks) {
              mActivityLifecycleCallbacks.remove(callback);
          }
      }
  
      public void registerOnProvideAssistDataListener(OnProvideAssistDataListener callback) {
          synchronized (this) {
              if (mAssistCallbacks == null) {
                  mAssistCallbacks = new ArrayList<OnProvideAssistDataListener>();
              }
              mAssistCallbacks.add(callback);
          }
      }
  
      public void unregisterOnProvideAssistDataListener(OnProvideAssistDataListener callback) {
          synchronized (this) {
              if (mAssistCallbacks != null) {
                  mAssistCallbacks.remove(callback);
              }
          }
      }
  
      /**
       * Returns the name of the current process. A package's default process name
       * is the same as its package name. Non-default processes will look like
       * "$PACKAGE_NAME:$NAME", where $NAME corresponds to an android:process
       * attribute within AndroidManifest.xml.
       */
      public static String getProcessName() {
          return ActivityThread.currentProcessName();
      }
  
      // ------------------ Internal API ------------------
  
      /**
       * @hide
       */
      @UnsupportedAppUsage
      /* package */ final void attach(Context context) {
          attachBaseContext(context);
          mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
      }
  
      @UnsupportedAppUsage
          /* package */ void dispatchActivityPreCreated(@NonNull Activity activity,
              @Nullable Bundle savedInstanceState) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i = 0; i < callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreCreated(activity,
                          savedInstanceState);
              }
          }
      }
  
      @UnsupportedAppUsage
      /* package */ void dispatchActivityCreated(@NonNull Activity activity,
              @Nullable Bundle savedInstanceState) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i=0; i<callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks)callbacks[i]).onActivityCreated(activity,
                          savedInstanceState);
              }
          }
      }
  
      @UnsupportedAppUsage
          /* package */ void dispatchActivityPostCreated(@NonNull Activity activity,
              @Nullable Bundle savedInstanceState) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i = 0; i < callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostCreated(activity,
                          savedInstanceState);
              }
          }
      }
  
      @UnsupportedAppUsage
          /* package */ void dispatchActivityPreStarted(@NonNull Activity activity) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i = 0; i < callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreStarted(activity);
              }
          }
      }
  
      @UnsupportedAppUsage
      /* package */ void dispatchActivityStarted(@NonNull Activity activity) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i=0; i<callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks)callbacks[i]).onActivityStarted(activity);
              }
          }
      }
  
      @UnsupportedAppUsage
          /* package */ void dispatchActivityPostStarted(@NonNull Activity activity) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i = 0; i < callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostStarted(activity);
              }
          }
      }
  
      @UnsupportedAppUsage
          /* package */ void dispatchActivityPreResumed(@NonNull Activity activity) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i = 0; i < callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreResumed(activity);
              }
          }
      }
  
      @UnsupportedAppUsage
      /* package */ void dispatchActivityResumed(@NonNull Activity activity) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i=0; i<callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks)callbacks[i]).onActivityResumed(activity);
              }
          }
      }
  
      @UnsupportedAppUsage
          /* package */ void dispatchActivityPostResumed(@NonNull Activity activity) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i = 0; i < callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostResumed(activity);
              }
          }
      }
  
      @UnsupportedAppUsage
          /* package */ void dispatchActivityPrePaused(@NonNull Activity activity) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i = 0; i < callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPrePaused(activity);
              }
          }
      }
  
      @UnsupportedAppUsage
      /* package */ void dispatchActivityPaused(@NonNull Activity activity) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i=0; i<callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks)callbacks[i]).onActivityPaused(activity);
              }
          }
      }
  
      @UnsupportedAppUsage
          /* package */ void dispatchActivityPostPaused(@NonNull Activity activity) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i = 0; i < callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostPaused(activity);
              }
          }
      }
  
      @UnsupportedAppUsage
          /* package */ void dispatchActivityPreStopped(@NonNull Activity activity) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i = 0; i < callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreStopped(activity);
              }
          }
      }
  
      @UnsupportedAppUsage
      /* package */ void dispatchActivityStopped(@NonNull Activity activity) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i=0; i<callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks)callbacks[i]).onActivityStopped(activity);
              }
          }
      }
  
      @UnsupportedAppUsage
          /* package */ void dispatchActivityPostStopped(@NonNull Activity activity) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i = 0; i < callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostStopped(activity);
              }
          }
      }
  
      @UnsupportedAppUsage
          /* package */ void dispatchActivityPreSaveInstanceState(@NonNull Activity activity,
              @NonNull Bundle outState) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i = 0; i < callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreSaveInstanceState(
                          activity, outState);
              }
          }
      }
  
      @UnsupportedAppUsage
      /* package */ void dispatchActivitySaveInstanceState(@NonNull Activity activity,
              @NonNull Bundle outState) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i=0; i<callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks)callbacks[i]).onActivitySaveInstanceState(activity,
                          outState);
              }
          }
      }
  
      @UnsupportedAppUsage
          /* package */ void dispatchActivityPostSaveInstanceState(@NonNull Activity activity,
              @NonNull Bundle outState) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i = 0; i < callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostSaveInstanceState(
                          activity, outState);
              }
          }
      }
  
      @UnsupportedAppUsage
          /* package */ void dispatchActivityPreDestroyed(@NonNull Activity activity) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i = 0; i < callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreDestroyed(activity);
              }
          }
      }
  
      @UnsupportedAppUsage
      /* package */ void dispatchActivityDestroyed(@NonNull Activity activity) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i=0; i<callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks)callbacks[i]).onActivityDestroyed(activity);
              }
          }
      }
  
      @UnsupportedAppUsage
          /* package */ void dispatchActivityPostDestroyed(@NonNull Activity activity) {
          Object[] callbacks = collectActivityLifecycleCallbacks();
          if (callbacks != null) {
              for (int i = 0; i < callbacks.length; i++) {
                  ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostDestroyed(activity);
              }
          }
      }
  
      private Object[] collectComponentCallbacks() {
          Object[] callbacks = null;
          synchronized (mComponentCallbacks) {
              if (mComponentCallbacks.size() > 0) {
                  callbacks = mComponentCallbacks.toArray();
              }
          }
          return callbacks;
      }
  
      @UnsupportedAppUsage
      private Object[] collectActivityLifecycleCallbacks() {
          Object[] callbacks = null;
          synchronized (mActivityLifecycleCallbacks) {
              if (mActivityLifecycleCallbacks.size() > 0) {
                  callbacks = mActivityLifecycleCallbacks.toArray();
              }
          }
          return callbacks;
      }
  
      /* package */ void dispatchOnProvideAssistData(Activity activity, Bundle data) {
          Object[] callbacks;
          synchronized (this) {
              if (mAssistCallbacks == null) {
                  return;
              }
              callbacks = mAssistCallbacks.toArray();
          }
          if (callbacks != null) {
              for (int i=0; i<callbacks.length; i++) {
                  ((OnProvideAssistDataListener)callbacks[i]).onProvideAssistData(activity, data);
              }
          }
      }
  
      /** @hide */
      @Override
      public AutofillManager.AutofillClient getAutofillClient() {
          final AutofillManager.AutofillClient client = super.getAutofillClient();
          if (client != null) {
              return client;
          }
          if (android.view.autofill.Helper.sVerbose) {
              Log.v(TAG, "getAutofillClient(): null on super, trying to find activity thread");
          }
          // Okay, ppl use the application context when they should not. This breaks
          // autofill among other things. We pick the focused activity since autofill
          // interacts only with the currently focused activity and we need the fill
          // client only if a call comes from the focused activity. Sigh...
          final ActivityThread activityThread = ActivityThread.currentActivityThread();
          if (activityThread == null) {
              return null;
          }
          final int activityCount = activityThread.mActivities.size();
          for (int i = 0; i < activityCount; i++) {
              final ActivityThread.ActivityClientRecord record =
                      activityThread.mActivities.valueAt(i);
              if (record == null) {
                  continue;
              }
              final Activity activity = record.activity;
              if (activity == null) {
                  continue;
              }
              if (activity.getWindow().getDecorView().hasFocus()) {
                  if (android.view.autofill.Helper.sVerbose) {
                      Log.v(TAG, "getAutofillClient(): found activity for " + this + ": " + activity);
                  }
                  return activity;
              }
          }
          if (android.view.autofill.Helper.sVerbose) {
              Log.v(TAG, "getAutofillClient(): none of the " + activityCount + " activities on "
                      + this + " have focus");
          }
          return null;
      }
  }
  