Permalink
Switch branches/tags
studio-3.1.2 studio-3.0 studio-2.3 gradle_3.1.2 gradle_3.0.0 gradle_2.3.0 android-wear-p-preview-2 android-wear-o-preview-4 android-wear-o-preview-3 android-wear-n-preview-2 android-wear-n-preview-1 android-wear-8.0.0_r1 android-wear-7.1.1_r1 android-wear-5.1.1_r1 android-wear-5.1.0_r1 android-wear-5.0.0_r1 android-vts-8.1_r5 android-vts-8.1_r4 android-vts-8.1_r3 android-vts-8.0_r8 android-vts-8.0_r7 android-vts-8.0_r6 android-vts-8.0_r2 android-vts-8.0_r1 android-sdk-support_r11 android-sdk-adt_r20 android-sdk-adt_r16.0.1 android-sdk-4.4.2_r1.0.1 android-sdk-4.4.2_r1 android-sdk-4.0.3_r1 android-sdk-4.0.3-tools_r1 android-p-preview-5 android-p-preview-4 android-p-preview-3 android-p-preview-2 android-p-preview-1 android-o-preview-4 android-o-preview-3 android-o-preview-2 android-o-preview-1 android-o-mr1-preview-2 android-o-mr1-preview-1 android-o-mr1-iot-release-1.0.4 android-o-mr1-iot-release-1.0.3 android-o-mr1-iot-release-1.0.2 android-o-mr1-iot-release-1.0.1 android-o-mr1-iot-release-1.0.0 android-o-mr1-iot-preview-8 android-o-mr1-iot-preview-7 android-o-mr1-iot-preview-6 android-o-iot-preview-5 android-n-preview-5 android-n-preview-4 android-n-preview-3 android-n-preview-2 android-n-preview-1 android-n-mr2-preview-2 android-n-mr2-preview-1 android-n-mr1-preview-2 android-n-mr1-preview-1 android-n-iot-release-smart-display android-n-iot-release-smart-display-r2 android-n-iot-release-polk-at1 android-n-iot-release-lg-thinq-wk7 android-n-iot-preview-4 android-n-iot-preview-2 android-m-preview android-m-preview-2 android-m-preview-1 android-l-preview_r2 android-cts-verifier-4.0.3_r1 android-cts-verifier-4.0_r1 android-cts-9.0_r2 android-cts-9.0_r1 android-cts-8.1_r9 android-cts-8.1_r8 android-cts-8.1_r7 android-cts-8.1_r6 android-cts-8.1_r5 android-cts-8.1_r4 android-cts-8.1_r3 android-cts-8.1_r2 android-cts-8.1_r1 android-cts-8.0_r13 android-cts-8.0_r12 android-cts-8.0_r11 android-cts-8.0_r10 android-cts-8.0_r9 android-cts-8.0_r8 android-cts-8.0_r7 android-cts-8.0_r6 android-cts-8.0_r5 android-cts-8.0_r4 android-cts-8.0_r3 android-cts-8.0_r2 android-cts-8.0_r1 android-cts-7.1_r21 android-cts-7.1_r20 android-cts-7.1_r19 android-cts-7.1_r18
Nothing to show
Find file Copy path
8043 lines (7504 sloc) 330 KB
/*
* 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 static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static java.lang.Character.MIN_VALUE;
import android.annotation.CallSuper;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.IntDef;
import android.annotation.LayoutRes;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.StyleRes;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.app.VoiceInteractor.Request;
import android.app.admin.DevicePolicyManager;
import android.app.assist.AssistContent;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.CursorLoader;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.session.MediaController;
import android.net.Uri;
import android.os.BadParcelableException;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.StrictMode;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.method.TextKeyListener;
import android.transition.Scene;
import android.transition.TransitionManager;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SuperNotCalledException;
import android.view.ActionMode;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.ContextThemeWrapper;
import android.view.DragAndDropPermissions;
import android.view.DragEvent;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.RemoteAnimationDefinition;
import android.view.SearchEvent;
import android.view.View;
import android.view.View.OnCreateContextMenuListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewManager;
import android.view.ViewRootImpl;
import android.view.ViewRootImpl.ActivityConfigCallback;
import android.view.Window;
import android.view.Window.WindowControllerCallback;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillManager.AutofillClient;
import android.view.autofill.AutofillPopupWindow;
import android.view.autofill.IAutofillWindowPresenter;
import android.widget.AdapterView;
import android.widget.Toast;
import android.widget.Toolbar;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ToolbarActionBar;
import com.android.internal.app.WindowDecorActionBar;
import com.android.internal.policy.PhoneWindow;
import dalvik.system.VMRuntime;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
/**
* An activity is a single, focused thing that the user can do. Almost all
* activities interact with the user, so the Activity class takes care of
* creating a window for you in which you can place your UI with
* {@link #setContentView}. While activities are often presented to the user
* as full-screen windows, they can also be used in other ways: as floating
* windows (via a theme with {@link android.R.attr#windowIsFloating} set)
* or embedded inside of another activity (using {@link ActivityGroup}).
*
* There are two methods almost all subclasses of Activity will implement:
*
* <ul>
* <li> {@link #onCreate} is where you initialize your activity. Most
* importantly, here you will usually call {@link #setContentView(int)}
* with a layout resource defining your UI, and using {@link #findViewById}
* to retrieve the widgets in that UI that you need to interact with
* programmatically.
*
* <li> {@link #onPause} is where you deal with the user leaving your
* activity. Most importantly, any changes made by the user should at this
* point be committed (usually to the
* {@link android.content.ContentProvider} holding the data).
* </ul>
*
* <p>To be of use with {@link android.content.Context#startActivity Context.startActivity()}, all
* activity classes must have a corresponding
* {@link android.R.styleable#AndroidManifestActivity &lt;activity&gt;}
* declaration in their package's <code>AndroidManifest.xml</code>.</p>
*
* <p>Topics covered here:
* <ol>
* <li><a href="#Fragments">Fragments</a>
* <li><a href="#ActivityLifecycle">Activity Lifecycle</a>
* <li><a href="#ConfigurationChanges">Configuration Changes</a>
* <li><a href="#StartingActivities">Starting Activities and Getting Results</a>
* <li><a href="#SavingPersistentState">Saving Persistent State</a>
* <li><a href="#Permissions">Permissions</a>
* <li><a href="#ProcessLifecycle">Process Lifecycle</a>
* </ol>
*
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>The Activity class is an important part of an application's overall lifecycle,
* and the way activities are launched and put together is a fundamental
* part of the platform's application model. For a detailed perspective on the structure of an
* Android application and how activities behave, please read the
* <a href="{@docRoot}guide/topics/fundamentals.html">Application Fundamentals</a> and
* <a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back Stack</a>
* developer guides.</p>
*
* <p>You can also find a detailed discussion about how to create activities in the
* <a href="{@docRoot}guide/components/activities.html">Activities</a>
* developer guide.</p>
* </div>
*
* <a name="Fragments"></a>
* <h3>Fragments</h3>
*
* <p>The {@link android.support.v4.app.FragmentActivity} subclass
* can make use of the {@link android.support.v4.app.Fragment} class to better
* modularize their code, build more sophisticated user interfaces for larger
* screens, and help scale their application between small and large screens.</p>
*
* <p>For more information about using fragments, read the
* <a href="{@docRoot}guide/components/fragments.html">Fragments</a> developer guide.</p>
*
* <a name="ActivityLifecycle"></a>
* <h3>Activity Lifecycle</h3>
*
* <p>Activities in the system are managed as an <em>activity stack</em>.
* When a new activity is started, it is placed on the top of the stack
* and becomes the running activity -- the previous activity always remains
* below it in the stack, and will not come to the foreground again until
* the new activity exits.</p>
*
* <p>An activity has essentially four states:</p>
* <ul>
* <li> If an activity is in the foreground of the screen (at the top of
* the stack),
* it is <em>active</em> or <em>running</em>. </li>
* <li>If an activity has lost focus but is still visible (that is, a new non-full-sized
* or transparent activity has focus on top of your activity), it
* is <em>paused</em>. A paused activity is completely alive (it
* maintains all state and member information and remains attached to
* the window manager), but can be killed by the system in extreme
* low memory situations.
* <li>If an activity is completely obscured by another activity,
* it is <em>stopped</em>. It still retains all state and member information,
* however, it is no longer visible to the user so its window is hidden
* and it will often be killed by the system when memory is needed
* elsewhere.</li>
* <li>If an activity is paused or stopped, the system can drop the activity
* from memory by either asking it to finish, or simply killing its
* process. When it is displayed again to the user, it must be
* completely restarted and restored to its previous state.</li>
* </ul>
*
* <p>The following diagram shows the important state paths of an Activity.
* The square rectangles represent callback methods you can implement to
* perform operations when the Activity moves between states. The colored
* ovals are major states the Activity can be in.</p>
*
* <p><img src="../../../images/activity_lifecycle.png"
* alt="State diagram for an Android Activity Lifecycle." border="0" /></p>
*
* <p>There are three key loops you may be interested in monitoring within your
* activity:
*
* <ul>
* <li>The <b>entire lifetime</b> of an activity happens between the first call
* to {@link android.app.Activity#onCreate} through to a single final call
* to {@link android.app.Activity#onDestroy}. An activity will do all setup
* of "global" state in onCreate(), and release all remaining resources in
* onDestroy(). For example, if it has a thread running in the background
* to download data from the network, it may create that thread in onCreate()
* and then stop the thread in onDestroy().
*
* <li>The <b>visible lifetime</b> of an activity happens between a call to
* {@link android.app.Activity#onStart} until a corresponding call to
* {@link android.app.Activity#onStop}. During this time the user can see the
* activity on-screen, though it may not be in the foreground and interacting
* with the user. Between these two methods you can maintain resources that
* are needed to show the activity to the user. For example, you can register
* a {@link android.content.BroadcastReceiver} in onStart() to monitor for changes
* that impact your UI, and unregister it in onStop() when the user no
* longer sees what you are displaying. The onStart() and onStop() methods
* can be called multiple times, as the activity becomes visible and hidden
* to the user.
*
* <li>The <b>foreground lifetime</b> of an activity happens between a call to
* {@link android.app.Activity#onResume} until a corresponding call to
* {@link android.app.Activity#onPause}. During this time the activity is
* in front of all other activities and interacting with the user. An activity
* can frequently go between the resumed and paused states -- for example when
* the device goes to sleep, when an activity result is delivered, when a new
* intent is delivered -- so the code in these methods should be fairly
* lightweight.
* </ul>
*
* <p>The entire lifecycle of an activity is defined by the following
* Activity methods. All of these are hooks that you can override
* to do appropriate work when the activity changes state. All
* activities will implement {@link android.app.Activity#onCreate}
* to do their initial setup; many will also implement
* {@link android.app.Activity#onPause} to commit changes to data and
* otherwise prepare to stop interacting with the user. You should always
* call up to your superclass when implementing these methods.</p>
*
* </p>
* <pre class="prettyprint">
* public class Activity extends ApplicationContext {
* protected void onCreate(Bundle savedInstanceState);
*
* protected void onStart();
*
* protected void onRestart();
*
* protected void onResume();
*
* protected void onPause();
*
* protected void onStop();
*
* protected void onDestroy();
* }
* </pre>
*
* <p>In general the movement through an activity's lifecycle looks like
* this:</p>
*
* <table border="2" width="85%" align="center" frame="hsides" rules="rows">
* <colgroup align="left" span="3" />
* <colgroup align="left" />
* <colgroup align="center" />
* <colgroup align="center" />
*
* <thead>
* <tr><th colspan="3">Method</th> <th>Description</th> <th>Killable?</th> <th>Next</th></tr>
* </thead>
*
* <tbody>
* <tr><td colspan="3" align="left" border="0">{@link android.app.Activity#onCreate onCreate()}</td>
* <td>Called when the activity is first created.
* This is where you should do all of your normal static set up:
* create views, bind data to lists, etc. This method also
* provides you with a Bundle containing the activity's previously
* frozen state, if there was one.
* <p>Always followed by <code>onStart()</code>.</td>
* <td align="center">No</td>
* <td align="center"><code>onStart()</code></td>
* </tr>
*
* <tr><td rowspan="5" style="border-left: none; border-right: none;">&nbsp;&nbsp;&nbsp;&nbsp;</td>
* <td colspan="2" align="left" border="0">{@link android.app.Activity#onRestart onRestart()}</td>
* <td>Called after your activity has been stopped, prior to it being
* started again.
* <p>Always followed by <code>onStart()</code></td>
* <td align="center">No</td>
* <td align="center"><code>onStart()</code></td>
* </tr>
*
* <tr><td colspan="2" align="left" border="0">{@link android.app.Activity#onStart onStart()}</td>
* <td>Called when the activity is becoming visible to the user.
* <p>Followed by <code>onResume()</code> if the activity comes
* to the foreground, or <code>onStop()</code> if it becomes hidden.</td>
* <td align="center">No</td>
* <td align="center"><code>onResume()</code> or <code>onStop()</code></td>
* </tr>
*
* <tr><td rowspan="2" style="border-left: none;">&nbsp;&nbsp;&nbsp;&nbsp;</td>
* <td align="left" border="0">{@link android.app.Activity#onResume onResume()}</td>
* <td>Called when the activity will start
* interacting with the user. At this point your activity is at
* the top of the activity stack, with user input going to it.
* <p>Always followed by <code>onPause()</code>.</td>
* <td align="center">No</td>
* <td align="center"><code>onPause()</code></td>
* </tr>
*
* <tr><td align="left" border="0">{@link android.app.Activity#onPause onPause()}</td>
* <td>Called when the system is about to start resuming a previous
* activity. This is typically used to commit unsaved changes to
* persistent data, stop animations and other things that may be consuming
* CPU, etc. Implementations of this method must be very quick because
* the next activity will not be resumed until this method returns.
* <p>Followed by either <code>onResume()</code> if the activity
* returns back to the front, or <code>onStop()</code> if it becomes
* invisible to the user.</td>
* <td align="center"><font color="#800000"><strong>Pre-{@link android.os.Build.VERSION_CODES#HONEYCOMB}</strong></font></td>
* <td align="center"><code>onResume()</code> or<br>
* <code>onStop()</code></td>
* </tr>
*
* <tr><td colspan="2" align="left" border="0">{@link android.app.Activity#onStop onStop()}</td>
* <td>Called when the activity is no longer visible to the user, because
* another activity has been resumed and is covering this one. This
* may happen either because a new activity is being started, an existing
* one is being brought in front of this one, or this one is being
* destroyed.
* <p>Followed by either <code>onRestart()</code> if
* this activity is coming back to interact with the user, or
* <code>onDestroy()</code> if this activity is going away.</td>
* <td align="center"><font color="#800000"><strong>Yes</strong></font></td>
* <td align="center"><code>onRestart()</code> or<br>
* <code>onDestroy()</code></td>
* </tr>
*
* <tr><td colspan="3" align="left" border="0">{@link android.app.Activity#onDestroy onDestroy()}</td>
* <td>The final call you receive before your
* activity is destroyed. This can happen either because the
* activity is finishing (someone called {@link Activity#finish} on
* it, or because the system is temporarily destroying this
* instance of the activity to save space. You can distinguish
* between these two scenarios with the {@link
* Activity#isFinishing} method.</td>
* <td align="center"><font color="#800000"><strong>Yes</strong></font></td>
* <td align="center"><em>nothing</em></td>
* </tr>
* </tbody>
* </table>
*
* <p>Note the "Killable" column in the above table -- for those methods that
* are marked as being killable, after that method returns the process hosting the
* activity may be killed by the system <em>at any time</em> without another line
* of its code being executed. Because of this, you should use the
* {@link #onPause} method to write any persistent data (such as user edits)
* to storage. In addition, the method
* {@link #onSaveInstanceState(Bundle)} is called before placing the activity
* in such a background state, allowing you to save away any dynamic instance
* state in your activity into the given Bundle, to be later received in
* {@link #onCreate} if the activity needs to be re-created.
* See the <a href="#ProcessLifecycle">Process Lifecycle</a>
* section for more information on how the lifecycle of a process is tied
* to the activities it is hosting. Note that it is important to save
* persistent data in {@link #onPause} instead of {@link #onSaveInstanceState}
* because the latter is not part of the lifecycle callbacks, so will not
* be called in every situation as described in its documentation.</p>
*
* <p class="note">Be aware that these semantics will change slightly between
* applications targeting platforms starting with {@link android.os.Build.VERSION_CODES#HONEYCOMB}
* vs. those targeting prior platforms. Starting with Honeycomb, an application
* is not in the killable state until its {@link #onStop} has returned. This
* impacts when {@link #onSaveInstanceState(Bundle)} may be called (it may be
* safely called after {@link #onPause()}) and allows an application to safely
* wait until {@link #onStop()} to save persistent state.</p>
*
* <p class="note">For applications targeting platforms starting with
* {@link android.os.Build.VERSION_CODES#P} {@link #onSaveInstanceState(Bundle)}
* will always be called after {@link #onStop}, so an application may safely
* perform fragment transactions in {@link #onStop} and will be able to save
* persistent state later.</p>
*
* <p>For those methods that are not marked as being killable, the activity's
* process will not be killed by the system starting from the time the method
* is called and continuing after it returns. Thus an activity is in the killable
* state, for example, between after <code>onPause()</code> to the start of
* <code>onResume()</code>.</p>
*
* <a name="ConfigurationChanges"></a>
* <h3>Configuration Changes</h3>
*
* <p>If the configuration of the device (as defined by the
* {@link Configuration Resources.Configuration} class) changes,
* then anything displaying a user interface will need to update to match that
* configuration. Because Activity is the primary mechanism for interacting
* with the user, it includes special support for handling configuration
* changes.</p>
*
* <p>Unless you specify otherwise, a configuration change (such as a change
* in screen orientation, language, input devices, etc) will cause your
* current activity to be <em>destroyed</em>, going through the normal activity
* lifecycle process of {@link #onPause},
* {@link #onStop}, and {@link #onDestroy} as appropriate. If the activity
* had been in the foreground or visible to the user, once {@link #onDestroy} is
* called in that instance then a new instance of the activity will be
* created, with whatever savedInstanceState the previous instance had generated
* from {@link #onSaveInstanceState}.</p>
*
* <p>This is done because any application resource,
* including layout files, can change based on any configuration value. Thus
* the only safe way to handle a configuration change is to re-retrieve all
* resources, including layouts, drawables, and strings. Because activities
* must already know how to save their state and re-create themselves from
* that state, this is a convenient way to have an activity restart itself
* with a new configuration.</p>
*
* <p>In some special cases, you may want to bypass restarting of your
* activity based on one or more types of configuration changes. This is
* done with the {@link android.R.attr#configChanges android:configChanges}
* attribute in its manifest. For any types of configuration changes you say
* that you handle there, you will receive a call to your current activity's
* {@link #onConfigurationChanged} method instead of being restarted. If
* a configuration change involves any that you do not handle, however, the
* activity will still be restarted and {@link #onConfigurationChanged}
* will not be called.</p>
*
* <a name="StartingActivities"></a>
* <h3>Starting Activities and Getting Results</h3>
*
* <p>The {@link android.app.Activity#startActivity}
* method is used to start a
* new activity, which will be placed at the top of the activity stack. It
* takes a single argument, an {@link android.content.Intent Intent},
* which describes the activity
* to be executed.</p>
*
* <p>Sometimes you want to get a result back from an activity when it
* ends. For example, you may start an activity that lets the user pick
* a person in a list of contacts; when it ends, it returns the person
* that was selected. To do this, you call the
* {@link android.app.Activity#startActivityForResult(Intent, int)}
* version with a second integer parameter identifying the call. The result
* will come back through your {@link android.app.Activity#onActivityResult}
* method.</p>
*
* <p>When an activity exits, it can call
* {@link android.app.Activity#setResult(int)}
* to return data back to its parent. It must always supply a result code,
* which can be the standard results RESULT_CANCELED, RESULT_OK, or any
* custom values starting at RESULT_FIRST_USER. In addition, it can optionally
* return back an Intent containing any additional data it wants. All of this
* information appears back on the
* parent's <code>Activity.onActivityResult()</code>, along with the integer
* identifier it originally supplied.</p>
*
* <p>If a child activity fails for any reason (such as crashing), the parent
* activity will receive a result with the code RESULT_CANCELED.</p>
*
* <pre class="prettyprint">
* public class MyActivity extends Activity {
* ...
*
* static final int PICK_CONTACT_REQUEST = 0;
*
* public boolean onKeyDown(int keyCode, KeyEvent event) {
* if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
* // When the user center presses, let them pick a contact.
* startActivityForResult(
* new Intent(Intent.ACTION_PICK,
* new Uri("content://contacts")),
* PICK_CONTACT_REQUEST);
* return true;
* }
* return false;
* }
*
* protected void onActivityResult(int requestCode, int resultCode,
* Intent data) {
* if (requestCode == PICK_CONTACT_REQUEST) {
* if (resultCode == RESULT_OK) {
* // A contact was picked. Here we will just display it
* // to the user.
* startActivity(new Intent(Intent.ACTION_VIEW, data));
* }
* }
* }
* }
* </pre>
*
* <a name="SavingPersistentState"></a>
* <h3>Saving Persistent State</h3>
*
* <p>There are generally two kinds of persistent state than an activity
* will deal with: shared document-like data (typically stored in a SQLite
* database using a {@linkplain android.content.ContentProvider content provider})
* and internal state such as user preferences.</p>
*
* <p>For content provider data, we suggest that activities use a
* "edit in place" user model. That is, any edits a user makes are effectively
* made immediately without requiring an additional confirmation step.
* Supporting this model is generally a simple matter of following two rules:</p>
*
* <ul>
* <li> <p>When creating a new document, the backing database entry or file for
* it is created immediately. For example, if the user chooses to write
* a new email, a new entry for that email is created as soon as they
* start entering data, so that if they go to any other activity after
* that point this email will now appear in the list of drafts.</p>
* <li> <p>When an activity's <code>onPause()</code> method is called, it should
* commit to the backing content provider or file any changes the user
* has made. This ensures that those changes will be seen by any other
* activity that is about to run. You will probably want to commit
* your data even more aggressively at key times during your
* activity's lifecycle: for example before starting a new
* activity, before finishing your own activity, when the user
* switches between input fields, etc.</p>
* </ul>
*
* <p>This model is designed to prevent data loss when a user is navigating
* between activities, and allows the system to safely kill an activity (because
* system resources are needed somewhere else) at any time after it has been
* paused. Note this implies
* that the user pressing BACK from your activity does <em>not</em>
* mean "cancel" -- it means to leave the activity with its current contents
* saved away. Canceling edits in an activity must be provided through
* some other mechanism, such as an explicit "revert" or "undo" option.</p>
*
* <p>See the {@linkplain android.content.ContentProvider content package} for
* more information about content providers. These are a key aspect of how
* different activities invoke and propagate data between themselves.</p>
*
* <p>The Activity class also provides an API for managing internal persistent state
* associated with an activity. This can be used, for example, to remember
* the user's preferred initial display in a calendar (day view or week view)
* or the user's default home page in a web browser.</p>
*
* <p>Activity persistent state is managed
* with the method {@link #getPreferences},
* allowing you to retrieve and
* modify a set of name/value pairs associated with the activity. To use
* preferences that are shared across multiple application components
* (activities, receivers, services, providers), you can use the underlying
* {@link Context#getSharedPreferences Context.getSharedPreferences()} method
* to retrieve a preferences
* object stored under a specific name.
* (Note that it is not possible to share settings data across application
* packages -- for that you will need a content provider.)</p>
*
* <p>Here is an excerpt from a calendar activity that stores the user's
* preferred view mode in its persistent settings:</p>
*
* <pre class="prettyprint">
* public class CalendarActivity extends Activity {
* ...
*
* static final int DAY_VIEW_MODE = 0;
* static final int WEEK_VIEW_MODE = 1;
*
* private SharedPreferences mPrefs;
* private int mCurViewMode;
*
* protected void onCreate(Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
*
* SharedPreferences mPrefs = getSharedPreferences();
* mCurViewMode = mPrefs.getInt("view_mode", DAY_VIEW_MODE);
* }
*
* protected void onPause() {
* super.onPause();
*
* SharedPreferences.Editor ed = mPrefs.edit();
* ed.putInt("view_mode", mCurViewMode);
* ed.commit();
* }
* }
* </pre>
*
* <a name="Permissions"></a>
* <h3>Permissions</h3>
*
* <p>The ability to start a particular Activity can be enforced when it is
* declared in its
* manifest's {@link android.R.styleable#AndroidManifestActivity &lt;activity&gt;}
* tag. By doing so, other applications will need to declare a corresponding
* {@link android.R.styleable#AndroidManifestUsesPermission &lt;uses-permission&gt;}
* element in their own manifest to be able to start that activity.
*
* <p>When starting an Activity you can set {@link Intent#FLAG_GRANT_READ_URI_PERMISSION
* Intent.FLAG_GRANT_READ_URI_PERMISSION} and/or {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION
* Intent.FLAG_GRANT_WRITE_URI_PERMISSION} on the Intent. This will grant the
* Activity access to the specific URIs in the Intent. Access will remain
* until the Activity has finished (it will remain across the hosting
* process being killed and other temporary destruction). As of
* {@link android.os.Build.VERSION_CODES#GINGERBREAD}, if the Activity
* was already created and a new Intent is being delivered to
* {@link #onNewIntent(Intent)}, any newly granted URI permissions will be added
* to the existing ones it holds.
*
* <p>See the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
* document for more information on permissions and security in general.
*
* <a name="ProcessLifecycle"></a>
* <h3>Process Lifecycle</h3>
*
* <p>The Android system attempts to keep an application process around for as
* long as possible, but eventually will need to remove old processes when
* memory runs low. As described in <a href="#ActivityLifecycle">Activity
* Lifecycle</a>, the decision about which process to remove is intimately
* tied to the state of the user's interaction with it. In general, there
* are four states a process can be in based on the activities running in it,
* listed here in order of importance. The system will kill less important
* processes (the last ones) before it resorts to killing more important
* processes (the first ones).
*
* <ol>
* <li> <p>The <b>foreground activity</b> (the activity at the top of the screen
* that the user is currently interacting with) is considered the most important.
* Its process will only be killed as a last resort, if it uses more memory
* than is available on the device. Generally at this point the device has
* reached a memory paging state, so this is required in order to keep the user
* interface responsive.
* <li> <p>A <b>visible activity</b> (an activity that is visible to the user
* but not in the foreground, such as one sitting behind a foreground dialog)
* is considered extremely important and will not be killed unless that is
* required to keep the foreground activity running.
* <li> <p>A <b>background activity</b> (an activity that is not visible to
* the user and has been paused) is no longer critical, so the system may
* safely kill its process to reclaim memory for other foreground or
* visible processes. If its process needs to be killed, when the user navigates
* back to the activity (making it visible on the screen again), its
* {@link #onCreate} method will be called with the savedInstanceState it had previously
* supplied in {@link #onSaveInstanceState} so that it can restart itself in the same
* state as the user last left it.
* <li> <p>An <b>empty process</b> is one hosting no activities or other
* application components (such as {@link Service} or
* {@link android.content.BroadcastReceiver} classes). These are killed very
* quickly by the system as memory becomes low. For this reason, any
* background operation you do outside of an activity must be executed in the
* context of an activity BroadcastReceiver or Service to ensure that the system
* knows it needs to keep your process around.
* </ol>
*
* <p>Sometimes an Activity may need to do a long-running operation that exists
* independently of the activity lifecycle itself. An example may be a camera
* application that allows you to upload a picture to a web site. The upload
* may take a long time, and the application should allow the user to leave
* the application while it is executing. To accomplish this, your Activity
* should start a {@link Service} in which the upload takes place. This allows
* the system to properly prioritize your process (considering it to be more
* important than other non-visible applications) for the duration of the
* upload, independent of whether the original activity is paused, stopped,
* or finished.
*/
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback, WindowControllerCallback,
AutofillManager.AutofillClient {
private static final String TAG = "Activity";
private static final boolean DEBUG_LIFECYCLE = false;
/** Standard activity result: operation canceled. */
public static final int RESULT_CANCELED = 0;
/** Standard activity result: operation succeeded. */
public static final int RESULT_OK = -1;
/** Start of user-defined activity results. */
public static final int RESULT_FIRST_USER = 1;
/** @hide Task isn't finished when activity is finished */
public static final int DONT_FINISH_TASK_WITH_ACTIVITY = 0;
/**
* @hide Task is finished if the finishing activity is the root of the task. To preserve the
* past behavior the task is also removed from recents.
*/
public static final int FINISH_TASK_WITH_ROOT_ACTIVITY = 1;
/**
* @hide Task is finished along with the finishing activity, but it is not removed from
* recents.
*/
public static final int FINISH_TASK_WITH_ACTIVITY = 2;
@UnsupportedAppUsage
static final String FRAGMENTS_TAG = "android:fragments";
private static final String LAST_AUTOFILL_ID = "android:lastAutofillId";
private static final String AUTOFILL_RESET_NEEDED = "@android:autofillResetNeeded";
private static final String WINDOW_HIERARCHY_TAG = "android:viewHierarchyState";
private static final String SAVED_DIALOG_IDS_KEY = "android:savedDialogIds";
private static final String SAVED_DIALOGS_TAG = "android:savedDialogs";
private static final String SAVED_DIALOG_KEY_PREFIX = "android:dialog_";
private static final String SAVED_DIALOG_ARGS_KEY_PREFIX = "android:dialog_args_";
private static final String HAS_CURENT_PERMISSIONS_REQUEST_KEY =
"android:hasCurrentPermissionsRequest";
private static final String REQUEST_PERMISSIONS_WHO_PREFIX = "@android:requestPermissions:";
private static final String AUTO_FILL_AUTH_WHO_PREFIX = "@android:autoFillAuth:";
private static final String KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME = "com.android.systemui";
private static final int LOG_AM_ON_CREATE_CALLED = 30057;
private static final int LOG_AM_ON_START_CALLED = 30059;
private static final int LOG_AM_ON_RESUME_CALLED = 30022;
private static final int LOG_AM_ON_PAUSE_CALLED = 30021;
private static final int LOG_AM_ON_STOP_CALLED = 30049;
private static final int LOG_AM_ON_RESTART_CALLED = 30058;
private static final int LOG_AM_ON_DESTROY_CALLED = 30060;
private static final int LOG_AM_ON_ACTIVITY_RESULT_CALLED = 30062;
private static class ManagedDialog {
Dialog mDialog;
Bundle mArgs;
}
private SparseArray<ManagedDialog> mManagedDialogs;
// set by the thread after the constructor and before onCreate(Bundle savedInstanceState) is called.
@UnsupportedAppUsage
private Instrumentation mInstrumentation;
@UnsupportedAppUsage
private IBinder mToken;
@UnsupportedAppUsage
private int mIdent;
@UnsupportedAppUsage
/*package*/ String mEmbeddedID;
@UnsupportedAppUsage
private Application mApplication;
@UnsupportedAppUsage
/*package*/ Intent mIntent;
@UnsupportedAppUsage
/*package*/ String mReferrer;
@UnsupportedAppUsage
private ComponentName mComponent;
@UnsupportedAppUsage
/*package*/ ActivityInfo mActivityInfo;
@UnsupportedAppUsage
/*package*/ ActivityThread mMainThread;
@UnsupportedAppUsage
Activity mParent;
@UnsupportedAppUsage
boolean mCalled;
@UnsupportedAppUsage
/*package*/ boolean mResumed;
@UnsupportedAppUsage
/*package*/ boolean mStopped;
@UnsupportedAppUsage
boolean mFinished;
boolean mStartedActivity;
@UnsupportedAppUsage
private boolean mDestroyed;
private boolean mDoReportFullyDrawn = true;
private boolean mRestoredFromBundle;
/** {@code true} if the activity lifecycle is in a state which supports picture-in-picture.
* This only affects the client-side exception, the actual state check still happens in AMS. */
private boolean mCanEnterPictureInPicture = false;
/** true if the activity is going through a transient pause */
/*package*/ boolean mTemporaryPause = false;
/** true if the activity is being destroyed in order to recreate it with a new configuration */
/*package*/ boolean mChangingConfigurations = false;
@UnsupportedAppUsage
/*package*/ int mConfigChangeFlags;
@UnsupportedAppUsage
/*package*/ Configuration mCurrentConfig;
private SearchManager mSearchManager;
private MenuInflater mMenuInflater;
/** The autofill manager. Always access via {@link #getAutofillManager()}. */
@Nullable private AutofillManager mAutofillManager;
static final class NonConfigurationInstances {
Object activity;
HashMap<String, Object> children;
FragmentManagerNonConfig fragments;
ArrayMap<String, LoaderManager> loaders;
VoiceInteractor voiceInteractor;
}
@UnsupportedAppUsage
/* package */ NonConfigurationInstances mLastNonConfigurationInstances;
@UnsupportedAppUsage
private Window mWindow;
@UnsupportedAppUsage
private WindowManager mWindowManager;
/*package*/ View mDecor = null;
@UnsupportedAppUsage
/*package*/ boolean mWindowAdded = false;
/*package*/ boolean mVisibleFromServer = false;
@UnsupportedAppUsage
/*package*/ boolean mVisibleFromClient = true;
/*package*/ ActionBar mActionBar = null;
private boolean mEnableDefaultActionBarUp;
@UnsupportedAppUsage
private VoiceInteractor mVoiceInteractor;
@UnsupportedAppUsage
private CharSequence mTitle;
private int mTitleColor = 0;
// we must have a handler before the FragmentController is constructed
@UnsupportedAppUsage
final Handler mHandler = new Handler();
@UnsupportedAppUsage
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
private static final class ManagedCursor {
ManagedCursor(Cursor cursor) {
mCursor = cursor;
mReleased = false;
mUpdated = false;
}
private final Cursor mCursor;
private boolean mReleased;
private boolean mUpdated;
}
@GuardedBy("mManagedCursors")
private final ArrayList<ManagedCursor> mManagedCursors = new ArrayList<>();
@GuardedBy("this")
@UnsupportedAppUsage
int mResultCode = RESULT_CANCELED;
@GuardedBy("this")
@UnsupportedAppUsage
Intent mResultData = null;
private TranslucentConversionListener mTranslucentCallback;
private boolean mChangeCanvasToTranslucent;
private SearchEvent mSearchEvent;
private boolean mTitleReady = false;
private int mActionModeTypeStarting = ActionMode.TYPE_PRIMARY;
private int mDefaultKeyMode = DEFAULT_KEYS_DISABLE;
private SpannableStringBuilder mDefaultKeySsb = null;
private ActivityManager.TaskDescription mTaskDescription =
new ActivityManager.TaskDescription();
protected static final int[] FOCUSED_STATE_SET = {com.android.internal.R.attr.state_focused};
@SuppressWarnings("unused")
private final Object mInstanceTracker = StrictMode.trackActivity(this);
private Thread mUiThread;
@UnsupportedAppUsage
ActivityTransitionState mActivityTransitionState = new ActivityTransitionState();
SharedElementCallback mEnterTransitionListener = SharedElementCallback.NULL_CALLBACK;
SharedElementCallback mExitTransitionListener = SharedElementCallback.NULL_CALLBACK;
private boolean mHasCurrentPermissionsRequest;
private boolean mAutoFillResetNeeded;
private boolean mAutoFillIgnoreFirstResumePause;
/** The last autofill id that was returned from {@link #getNextAutofillId()} */
private int mLastAutofillId = View.LAST_APP_AUTOFILL_ID;
private AutofillPopupWindow mAutofillPopupWindow;
private static native String getDlWarning();
/** Return the intent that started this activity. */
public Intent getIntent() {
return mIntent;
}
/**
* Change the intent returned by {@link #getIntent}. This holds a
* reference to the given intent; it does not copy it. Often used in
* conjunction with {@link #onNewIntent}.
*
* @param newIntent The new Intent object to return from getIntent
*
* @see #getIntent
* @see #onNewIntent
*/
public void setIntent(Intent newIntent) {
mIntent = newIntent;
}
/** Return the application that owns this activity. */
public final Application getApplication() {
return mApplication;
}
/** Is this activity embedded inside of another activity? */
public final boolean isChild() {
return mParent != null;
}
/** Return the parent activity if this view is an embedded child. */
public final Activity getParent() {
return mParent;
}
/** Retrieve the window manager for showing custom windows. */
public WindowManager getWindowManager() {
return mWindowManager;
}
/**
* Retrieve the current {@link android.view.Window} for the activity.
* This can be used to directly access parts of the Window API that
* are not available through Activity/Screen.
*
* @return Window The current window, or null if the activity is not
* visual.
*/
public Window getWindow() {
return mWindow;
}
/**
* Return the LoaderManager for this activity, creating it if needed.
*
* @deprecated Use {@link android.support.v4.app.FragmentActivity#getSupportLoaderManager()}
*/
@Deprecated
public LoaderManager getLoaderManager() {
return mFragments.getLoaderManager();
}
/**
* Calls {@link android.view.Window#getCurrentFocus} on the
* Window of this Activity to return the currently focused view.
*
* @return View The current View with focus or null.
*
* @see #getWindow
* @see android.view.Window#getCurrentFocus
*/
@Nullable
public View getCurrentFocus() {
return mWindow != null ? mWindow.getCurrentFocus() : null;
}
/**
* (Create and) return the autofill manager
*
* @return The autofill manager
*/
@NonNull private AutofillManager getAutofillManager() {
if (mAutofillManager == null) {
mAutofillManager = getSystemService(AutofillManager.class);
}
return mAutofillManager;
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
if (newBase != null) {
newBase.setAutofillClient(this);
}
}
/** @hide */
@Override
public final AutofillClient getAutofillClient() {
return this;
}
/**
* Called when the activity is starting. This is where most initialization
* should go: calling {@link #setContentView(int)} to inflate the
* activity's UI, using {@link #findViewById} to programmatically interact
* with widgets in the UI, calling
* {@link #managedQuery(android.net.Uri , String[], String, String[], String)} to retrieve
* cursors for data being displayed, etc.
*
* <p>You can call {@link #finish} from within this function, in
* which case onDestroy() will be immediately called after {@link #onCreate} without any of the
* rest of the activity lifecycle ({@link #onStart}, {@link #onResume}, {@link #onPause}, etc)
* executing.
*
* <p><em>Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
* thrown.</em></p>
*
* @param savedInstanceState If the activity is being re-initialized after
* previously being shut down then this Bundle contains the data it most
* recently supplied in {@link #onSaveInstanceState}. <b><i>Note: Otherwise it is null.</i></b>
*
* @see #onStart
* @see #onSaveInstanceState
* @see #onRestoreInstanceState
* @see #onPostCreate
*/
@MainThread
@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
if (mLastNonConfigurationInstances != null) {
mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
}
if (mActivityInfo.parentActivityName != null) {
if (mActionBar == null) {
mEnableDefaultActionBarUp = true;
} else {
mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
}
}
if (savedInstanceState != null) {
mAutoFillResetNeeded = savedInstanceState.getBoolean(AUTOFILL_RESET_NEEDED, false);
mLastAutofillId = savedInstanceState.getInt(LAST_AUTOFILL_ID,
View.LAST_APP_AUTOFILL_ID);
if (mAutoFillResetNeeded) {
getAutofillManager().onCreate(savedInstanceState);
}
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.fragments : null);
}
mFragments.dispatchCreate();
getApplication().dispatchActivityCreated(this, savedInstanceState);
if (mVoiceInteractor != null) {
mVoiceInteractor.attachActivity(this);
}
mRestoredFromBundle = savedInstanceState != null;
mCalled = true;
}
/**
* Same as {@link #onCreate(android.os.Bundle)} but called for those activities created with
* the attribute {@link android.R.attr#persistableMode} set to
* <code>persistAcrossReboots</code>.
*
* @param savedInstanceState if the activity is being re-initialized after
* previously being shut down then this Bundle contains the data it most
* recently supplied in {@link #onSaveInstanceState}.
* <b><i>Note: Otherwise it is null.</i></b>
* @param persistentState if the activity is being re-initialized after
* previously being shut down or powered off then this Bundle contains the data it most
* recently supplied to outPersistentState in {@link #onSaveInstanceState}.
* <b><i>Note: Otherwise it is null.</i></b>
*
* @see #onCreate(android.os.Bundle)
* @see #onStart
* @see #onSaveInstanceState
* @see #onRestoreInstanceState
* @see #onPostCreate
*/
public void onCreate(@Nullable Bundle savedInstanceState,
@Nullable PersistableBundle persistentState) {
onCreate(savedInstanceState);
}
/**
* The hook for {@link ActivityThread} to restore the state of this activity.
*
* Calls {@link #onSaveInstanceState(android.os.Bundle)} and
* {@link #restoreManagedDialogs(android.os.Bundle)}.
*
* @param savedInstanceState contains the saved state
*/
final void performRestoreInstanceState(Bundle savedInstanceState) {
onRestoreInstanceState(savedInstanceState);
restoreManagedDialogs(savedInstanceState);
}
/**
* The hook for {@link ActivityThread} to restore the state of this activity.
*
* Calls {@link #onSaveInstanceState(android.os.Bundle)} and
* {@link #restoreManagedDialogs(android.os.Bundle)}.
*
* @param savedInstanceState contains the saved state
* @param persistentState contains the persistable saved state
*/
final void performRestoreInstanceState(Bundle savedInstanceState,
PersistableBundle persistentState) {
onRestoreInstanceState(savedInstanceState, persistentState);
if (savedInstanceState != null) {
restoreManagedDialogs(savedInstanceState);
}
}
/**
* This method is called after {@link #onStart} when the activity is
* being re-initialized from a previously saved state, given here in
* <var>savedInstanceState</var>. Most implementations will simply use {@link #onCreate}
* to restore their state, but it is sometimes convenient to do it here
* after all of the initialization has been done or to allow subclasses to
* decide whether to use your default implementation. The default
* implementation of this method performs a restore of any view state that
* had previously been frozen by {@link #onSaveInstanceState}.
*
* <p>This method is called between {@link #onStart} and
* {@link #onPostCreate}.
*
* @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
*
* @see #onCreate
* @see #onPostCreate
* @see #onResume
* @see #onSaveInstanceState
*/
protected void onRestoreInstanceState(Bundle savedInstanceState) {
if (mWindow != null) {
Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
if (windowState != null) {
mWindow.restoreHierarchyState(windowState);
}
}
}
/**
* This is the same as {@link #onRestoreInstanceState(Bundle)} but is called for activities
* created with the attribute {@link android.R.attr#persistableMode} set to
* <code>persistAcrossReboots</code>. The {@link android.os.PersistableBundle} passed
* came from the restored PersistableBundle first
* saved in {@link #onSaveInstanceState(Bundle, PersistableBundle)}.
*
* <p>This method is called between {@link #onStart} and
* {@link #onPostCreate}.
*
* <p>If this method is called {@link #onRestoreInstanceState(Bundle)} will not be called.
*
* @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
* @param persistentState the data most recently supplied in {@link #onSaveInstanceState}.
*
* @see #onRestoreInstanceState(Bundle)
* @see #onCreate
* @see #onPostCreate
* @see #onResume
* @see #onSaveInstanceState
*/
public void onRestoreInstanceState(Bundle savedInstanceState,
PersistableBundle persistentState) {
if (savedInstanceState != null) {
onRestoreInstanceState(savedInstanceState);
}
}
/**
* Restore the state of any saved managed dialogs.
*
* @param savedInstanceState The bundle to restore from.
*/
private void restoreManagedDialogs(Bundle savedInstanceState) {
final Bundle b = savedInstanceState.getBundle(SAVED_DIALOGS_TAG);
if (b == null) {
return;
}
final int[] ids = b.getIntArray(SAVED_DIALOG_IDS_KEY);
final int numDialogs = ids.length;
mManagedDialogs = new SparseArray<ManagedDialog>(numDialogs);
for (int i = 0; i < numDialogs; i++) {
final Integer dialogId = ids[i];
Bundle dialogState = b.getBundle(savedDialogKeyFor(dialogId));
if (dialogState != null) {
// Calling onRestoreInstanceState() below will invoke dispatchOnCreate
// so tell createDialog() not to do it, otherwise we get an exception
final ManagedDialog md = new ManagedDialog();
md.mArgs = b.getBundle(savedDialogArgsKeyFor(dialogId));
md.mDialog = createDialog(dialogId, dialogState, md.mArgs);
if (md.mDialog != null) {
mManagedDialogs.put(dialogId, md);
onPrepareDialog(dialogId, md.mDialog, md.mArgs);
md.mDialog.onRestoreInstanceState(dialogState);
}
}
}
}
private Dialog createDialog(Integer dialogId, Bundle state, Bundle args) {
final Dialog dialog = onCreateDialog(dialogId, args);
if (dialog == null) {
return null;
}
dialog.dispatchOnCreate(state);
return dialog;
}
private static String savedDialogKeyFor(int key) {
return SAVED_DIALOG_KEY_PREFIX + key;
}
private static String savedDialogArgsKeyFor(int key) {
return SAVED_DIALOG_ARGS_KEY_PREFIX + key;
}
/**
* Called when activity start-up is complete (after {@link #onStart}
* and {@link #onRestoreInstanceState} have been called). Applications will
* generally not implement this method; it is intended for system
* classes to do final initialization after application code has run.
*
* <p><em>Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
* thrown.</em></p>
*
* @param savedInstanceState If the activity is being re-initialized after
* previously being shut down then this Bundle contains the data it most
* recently supplied in {@link #onSaveInstanceState}. <b><i>Note: Otherwise it is null.</i></b>
* @see #onCreate
*/
@CallSuper
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
if (!isChild()) {
mTitleReady = true;
onTitleChanged(getTitle(), getTitleColor());
}
mCalled = true;
}
/**
* This is the same as {@link #onPostCreate(Bundle)} but is called for activities
* created with the attribute {@link android.R.attr#persistableMode} set to
* <code>persistAcrossReboots</code>.
*
* @param savedInstanceState The data most recently supplied in {@link #onSaveInstanceState}
* @param persistentState The data caming from the PersistableBundle first
* saved in {@link #onSaveInstanceState(Bundle, PersistableBundle)}.
*
* @see #onCreate
*/
public void onPostCreate(@Nullable Bundle savedInstanceState,
@Nullable PersistableBundle persistentState) {
onPostCreate(savedInstanceState);
}
/**
* Called after {@link #onCreate} &mdash; or after {@link #onRestart} when
* the activity had been stopped, but is now again being displayed to the
* user. It will be followed by {@link #onResume}.
*
* <p><em>Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
* thrown.</em></p>
*
* @see #onCreate
* @see #onStop
* @see #onResume
*/
@CallSuper
protected void onStart() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
mCalled = true;
mFragments.doLoaderStart();
getApplication().dispatchActivityStarted(this);
if (mAutoFillResetNeeded) {
getAutofillManager().onVisibleForAutofill();
}
}
/**
* Called after {@link #onStop} when the current activity is being
* re-displayed to the user (the user has navigated back to it). It will
* be followed by {@link #onStart} and then {@link #onResume}.
*
* <p>For activities that are using raw {@link Cursor} objects (instead of
* creating them through
* {@link #managedQuery(android.net.Uri , String[], String, String[], String)},
* this is usually the place
* where the cursor should be requeried (because you had deactivated it in
* {@link #onStop}.
*
* <p><em>Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
* thrown.</em></p>
*
* @see #onStop
* @see #onStart
* @see #onResume
*/
@CallSuper
protected void onRestart() {
mCalled = true;
}
/**
* Called when an {@link #onResume} is coming up, prior to other pre-resume callbacks
* such as {@link #onNewIntent} and {@link #onActivityResult}. This is primarily intended
* to give the activity a hint that its state is no longer saved -- it will generally
* be called after {@link #onSaveInstanceState} and prior to the activity being
* resumed/started again.
*/
public void onStateNotSaved() {
}
/**
* Called after {@link #onRestoreInstanceState}, {@link #onRestart}, or
* {@link #onPause}, for your activity to start interacting with the user.
* This is a good place to begin animations, open exclusive-access devices
* (such as the camera), etc.
*
* <p>Keep in mind that onResume is not the best indicator that your activity
* is visible to the user; a system window such as the keyguard may be in
* front. Use {@link #onWindowFocusChanged} to know for certain that your
* activity is visible to the user (for example, to resume a game).
*
* <p><em>Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
* thrown.</em></p>
*
* @see #onRestoreInstanceState
* @see #onRestart
* @see #onPostResume
* @see #onPause
*/
@CallSuper
protected void onResume() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
getApplication().dispatchActivityResumed(this);
mActivityTransitionState.onResume(this, isTopOfTask());
if (mAutoFillResetNeeded) {
if (!mAutoFillIgnoreFirstResumePause) {
View focus = getCurrentFocus();
if (focus != null && focus.canNotifyAutofillEnterExitEvent()) {
// TODO: in Activity killed/recreated case, i.e. SessionLifecycleTest#
// testDatasetVisibleWhileAutofilledAppIsLifecycled: the View's initial
// window visibility after recreation is INVISIBLE in onResume() and next frame
// ViewRootImpl.performTraversals() changes window visibility to VISIBLE.
// So we cannot call View.notifyEnterOrExited() which will do nothing
// when View.isVisibleToUser() is false.
getAutofillManager().notifyViewEntered(focus);
}
}
}
mCalled = true;
}
/**
* Called when activity resume is complete (after {@link #onResume} has
* been called). Applications will generally not implement this method;
* it is intended for system classes to do final setup after application
* resume code has run.
*
* <p><em>Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
* thrown.</em></p>
*
* @see #onResume
*/
@CallSuper
protected void onPostResume() {
final Window win = getWindow();
if (win != null) win.makeActive();
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true);
mCalled = true;
}
void setVoiceInteractor(IVoiceInteractor voiceInteractor) {
if (mVoiceInteractor != null) {
for (Request activeRequest: mVoiceInteractor.getActiveRequests()) {
activeRequest.cancel();
activeRequest.clear();
}
}
if (voiceInteractor == null) {
mVoiceInteractor = null;
} else {
mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
Looper.myLooper());
}
}
/**
* Gets the next autofill ID.
*
* <p>All IDs will be bigger than {@link View#LAST_APP_AUTOFILL_ID}. All IDs returned
* will be unique.
*
* @return A ID that is unique in the activity
*
* {@hide}
*/
@Override
public int getNextAutofillId() {
if (mLastAutofillId == Integer.MAX_VALUE - 1) {
mLastAutofillId = View.LAST_APP_AUTOFILL_ID;
}
mLastAutofillId++;
return mLastAutofillId;
}
/**
* @hide
*/
@Override
public AutofillId autofillClientGetNextAutofillId() {
return new AutofillId(getNextAutofillId());
}
/**
* Check whether this activity is running as part of a voice interaction with the user.
* If true, it should perform its interaction with the user through the
* {@link VoiceInteractor} returned by {@link #getVoiceInteractor}.
*/
public boolean isVoiceInteraction() {
return mVoiceInteractor != null;
}
/**
* Like {@link #isVoiceInteraction}, but only returns true if this is also the root
* of a voice interaction. That is, returns true if this activity was directly
* started by the voice interaction service as the initiation of a voice interaction.
* Otherwise, for example if it was started by another activity while under voice
* interaction, returns false.
*/
public boolean isVoiceInteractionRoot() {
try {
return mVoiceInteractor != null
&& ActivityManager.getService().isRootVoiceInteraction(mToken);
} catch (RemoteException e) {
}
return false;
}
/**
* Retrieve the active {@link VoiceInteractor} that the user is going through to
* interact with this activity.
*/
public VoiceInteractor getVoiceInteractor() {
return mVoiceInteractor;
}
/**
* Queries whether the currently enabled voice interaction service supports returning
* a voice interactor for use by the activity. This is valid only for the duration of the
* activity.
*
* @return whether the current voice interaction service supports local voice interaction
*/
public boolean isLocalVoiceInteractionSupported() {
try {
return ActivityManager.getService().supportsLocalVoiceInteraction();
} catch (RemoteException re) {
}
return false;
}
/**
* Starts a local voice interaction session. When ready,
* {@link #onLocalVoiceInteractionStarted()} is called. You can pass a bundle of private options
* to the registered voice interaction service.
* @param privateOptions a Bundle of private arguments to the current voice interaction service
*/
public void startLocalVoiceInteraction(Bundle privateOptions) {
try {
ActivityManager.getService().startLocalVoiceInteraction(mToken, privateOptions);
} catch (RemoteException re) {
}
}
/**
* Callback to indicate that {@link #startLocalVoiceInteraction(Bundle)} has resulted in a
* voice interaction session being started. You can now retrieve a voice interactor using
* {@link #getVoiceInteractor()}.
*/
public void onLocalVoiceInteractionStarted() {
}
/**
* Callback to indicate that the local voice interaction has stopped either
* because it was requested through a call to {@link #stopLocalVoiceInteraction()}
* or because it was canceled by the user. The previously acquired {@link VoiceInteractor}
* is no longer valid after this.
*/
public void onLocalVoiceInteractionStopped() {
}
/**
* Request to terminate the current voice interaction that was previously started
* using {@link #startLocalVoiceInteraction(Bundle)}. When the interaction is
* terminated, {@link #onLocalVoiceInteractionStopped()} will be called.
*/
public void stopLocalVoiceInteraction() {
try {
ActivityManager.getService().stopLocalVoiceInteraction(mToken);
} catch (RemoteException re) {
}
}
/**
* This is called for activities that set launchMode to "singleTop" in
* their package, or if a client used the {@link Intent#FLAG_ACTIVITY_SINGLE_TOP}
* flag when calling {@link #startActivity}. In either case, when the
* activity is re-launched while at the top of the activity stack instead
* of a new instance of the activity being started, onNewIntent() will be
* called on the existing instance with the Intent that was used to
* re-launch it.
*
* <p>An activity will always be paused before receiving a new intent, so
* you can count on {@link #onResume} being called after this method.
*
* <p>Note that {@link #getIntent} still returns the original Intent. You
* can use {@link #setIntent} to update it to this new Intent.
*
* @param intent The new intent that was started for the activity.
*
* @see #getIntent
* @see #setIntent
* @see #onResume
*/
protected void onNewIntent(Intent intent) {
}
/**
* The hook for {@link ActivityThread} to save the state of this activity.
*
* Calls {@link #onSaveInstanceState(android.os.Bundle)}
* and {@link #saveManagedDialogs(android.os.Bundle)}.
*
* @param outState The bundle to save the state to.
*/
final void performSaveInstanceState(Bundle outState) {
onSaveInstanceState(outState);
saveManagedDialogs(outState);
mActivityTransitionState.saveState(outState);
storeHasCurrentPermissionRequest(outState);
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState);
}
/**
* The hook for {@link ActivityThread} to save the state of this activity.
*
* Calls {@link #onSaveInstanceState(android.os.Bundle)}
* and {@link #saveManagedDialogs(android.os.Bundle)}.
*
* @param outState The bundle to save the state to.
* @param outPersistentState The bundle to save persistent state to.
*/
final void performSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
onSaveInstanceState(outState, outPersistentState);
saveManagedDialogs(outState);
storeHasCurrentPermissionRequest(outState);
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState +
", " + outPersistentState);
}
/**
* Called to retrieve per-instance state from an activity before being killed
* so that the state can be restored in {@link #onCreate} or
* {@link #onRestoreInstanceState} (the {@link Bundle} populated by this method
* will be passed to both).
*
* <p>This method is called before an activity may be killed so that when it
* comes back some time in the future it can restore its state. For example,
* if activity B is launched in front of activity A, and at some point activity
* A is killed to reclaim resources, activity A will have a chance to save the
* current state of its user interface via this method so that when the user
* returns to activity A, the state of the user interface can be restored
* via {@link #onCreate} or {@link #onRestoreInstanceState}.
*
* <p>Do not confuse this method with activity lifecycle callbacks such as
* {@link #onPause}, which is always called when an activity is being placed
* in the background or on its way to destruction, or {@link #onStop} which
* is called before destruction. One example of when {@link #onPause} and
* {@link #onStop} is called and not this method is when a user navigates back
* from activity B to activity A: there is no need to call {@link #onSaveInstanceState}
* on B because that particular instance will never be restored, so the
* system avoids calling it. An example when {@link #onPause} is called and
* not {@link #onSaveInstanceState} is when activity B is launched in front of activity A:
* the system may avoid calling {@link #onSaveInstanceState} on activity A if it isn't
* killed during the lifetime of B since the state of the user interface of
* A will stay intact.
*
* <p>The default implementation takes care of most of the UI per-instance
* state for you by calling {@link android.view.View#onSaveInstanceState()} on each
* view in the hierarchy that has an id, and by saving the id of the currently
* focused view (all of which is restored by the default implementation of
* {@link #onRestoreInstanceState}). If you override this method to save additional
* information not captured by each individual view, you will likely want to
* call through to the default implementation, otherwise be prepared to save
* all of the state of each view yourself.
*
* <p>If called, this method will occur after {@link #onStop} for applications
* targeting platforms starting with {@link android.os.Build.VERSION_CODES#P}.
* For applications targeting earlier platform versions this method will occur
* before {@link #onStop} and there are no guarantees about whether it will
* occur before or after {@link #onPause}.
*
* @param outState Bundle in which to place your saved state.
*
* @see #onCreate
* @see #onRestoreInstanceState
* @see #onPause
*/
protected void onSaveInstanceState(Bundle outState) {
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
if (mAutoFillResetNeeded) {
outState.putBoolean(AUTOFILL_RESET_NEEDED, true);
getAutofillManager().onSaveInstanceState(outState);
}
getApplication().dispatchActivitySaveInstanceState(this, outState);
}
/**
* This is the same as {@link #onSaveInstanceState} but is called for activities
* created with the attribute {@link android.R.attr#persistableMode} set to
* <code>persistAcrossReboots</code>. The {@link android.os.PersistableBundle} passed
* in will be saved and presented in {@link #onCreate(Bundle, PersistableBundle)}
* the first time that this activity is restarted following the next device reboot.
*
* @param outState Bundle in which to place your saved state.
* @param outPersistentState State which will be saved across reboots.
*
* @see #onSaveInstanceState(Bundle)
* @see #onCreate
* @see #onRestoreInstanceState(Bundle, PersistableBundle)
* @see #onPause
*/
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
onSaveInstanceState(outState);
}
/**
* Save the state of any managed dialogs.
*
* @param outState place to store the saved state.
*/
@UnsupportedAppUsage
private void saveManagedDialogs(Bundle outState) {
if (mManagedDialogs == null) {
return;
}
final int numDialogs = mManagedDialogs.size();
if (numDialogs == 0) {
return;
}
Bundle dialogState = new Bundle();
int[] ids = new int[mManagedDialogs.size()];
// save each dialog's bundle, gather the ids
for (int i = 0; i < numDialogs; i++) {
final int key = mManagedDialogs.keyAt(i);
ids[i] = key;
final ManagedDialog md = mManagedDialogs.valueAt(i);
dialogState.putBundle(savedDialogKeyFor(key), md.mDialog.onSaveInstanceState());
if (md.mArgs != null) {
dialogState.putBundle(savedDialogArgsKeyFor(key), md.mArgs);
}
}
dialogState.putIntArray(SAVED_DIALOG_IDS_KEY, ids);
outState.putBundle(SAVED_DIALOGS_TAG, dialogState);
}
/**
* Called as part of the activity lifecycle when an activity is going into
* the background, but has not (yet) been killed. The counterpart to
* {@link #onResume}.
*
* <p>When activity B is launched in front of activity A, this callback will
* be invoked on A. B will not be created until A's {@link #onPause} returns,
* so be sure to not do anything lengthy here.
*
* <p>This callback is mostly used for saving any persistent state the
* activity is editing, to present a "edit in place" model to the user and
* making sure nothing is lost if there are not enough resources to start
* the new activity without first killing this one. This is also a good
* place to do things like stop animations and other things that consume a
* noticeable amount of CPU in order to make the switch to the next activity
* as fast as possible, or to close resources that are exclusive access
* such as the camera.
*
* <p>In situations where the system needs more memory it may kill paused
* processes to reclaim resources. Because of this, you should be sure
* that all of your state is saved by the time you return from
* this function. In general {@link #onSaveInstanceState} is used to save
* per-instance state in the activity and this method is used to store
* global persistent data (in content providers, files, etc.)
*
* <p>After receiving this call you will usually receive a following call
* to {@link #onStop} (after the next activity has been resumed and
* displayed), however in some cases there will be a direct call back to
* {@link #onResume} without going through the stopped state.
*
* <p><em>Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
* thrown.</em></p>
*
* @see #onResume
* @see #onSaveInstanceState
* @see #onStop
*/
@CallSuper
protected void onPause() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this);
getApplication().dispatchActivityPaused(this);
if (mAutoFillResetNeeded) {
if (!mAutoFillIgnoreFirstResumePause) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "autofill notifyViewExited " + this);
View focus = getCurrentFocus();
if (focus != null && focus.canNotifyAutofillEnterExitEvent()) {
getAutofillManager().notifyViewExited(focus);
}
} else {
// reset after first pause()
if (DEBUG_LIFECYCLE) Slog.v(TAG, "autofill got first pause " + this);
mAutoFillIgnoreFirstResumePause = false;
}
}
mCalled = true;
}
/**
* Called as part of the activity lifecycle when an activity is about to go
* into the background as the result of user choice. For example, when the
* user presses the Home key, {@link #onUserLeaveHint} will be called, but
* when an incoming phone call causes the in-call Activity to be automatically
* brought to the foreground, {@link #onUserLeaveHint} will not be called on
* the activity being interrupted. In cases when it is invoked, this method
* is called right before the activity's {@link #onPause} callback.
*
* <p>This callback and {@link #onUserInteraction} are intended to help
* activities manage status bar notifications intelligently; specifically,
* for helping activities determine the proper time to cancel a notification.
*
* @see #onUserInteraction()
*/
protected void onUserLeaveHint() {
}
/**
* @deprecated Method doesn't do anything and will be removed in the future.
*/
@Deprecated
public boolean onCreateThumbnail(Bitmap outBitmap, Canvas canvas) {
return false;
}
/**
* Generate a new description for this activity. This method is called
* before stopping the activity and can, if desired, return some textual
* description of its current state to be displayed to the user.
*
* <p>The default implementation returns null, which will cause you to
* inherit the description from the previous activity. If all activities
* return null, generally the label of the top activity will be used as the
* description.
*
* @return A description of what the user is doing. It should be short and
* sweet (only a few words).
*
* @see #onSaveInstanceState
* @see #onStop
*/
@Nullable
public CharSequence onCreateDescription() {
return null;
}
/**
* 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.
*
* <p>This function will be called after any global assist callbacks that had
* been registered with {@link Application#registerOnProvideAssistDataListener
* Application.registerOnProvideAssistDataListener}.
*/
public void onProvideAssistData(Bundle data) {
}
/**
* This is called when the user is requesting an assist, to provide references
* to content related to the current activity. Before being called, the
* {@code outContent} Intent is filled with the base Intent of the activity (the Intent
* returned by {@link #getIntent()}). The Intent's extras are stripped of any types
* that are not valid for {@link PersistableBundle} or non-framework Parcelables, and
* the flags {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION} and
* {@link Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION} are cleared from the Intent.
*
* <p>Custom implementation may adjust the content intent to better reflect the top-level
* context of the activity, and fill in its ClipData with additional content of
* interest that the user is currently viewing. For example, an image gallery application
* that has launched in to an activity allowing the user to swipe through pictures should
* modify the intent to reference the current image they are looking it; such an
* application when showing a list of pictures should add a ClipData that has
* references to all of the pictures currently visible on screen.</p>
*
* @param outContent The assist content to return.
*/
public void onProvideAssistContent(AssistContent outContent) {
}
/**
* Request the Keyboard Shortcuts screen to show up. This will trigger
* {@link #onProvideKeyboardShortcuts} to retrieve the shortcuts for the foreground activity.
*/
public final void requestShowKeyboardShortcuts() {
Intent intent = new Intent(Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS);
intent.setPackage(KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME);
sendBroadcastAsUser(intent, UserHandle.SYSTEM);
}
/**
* Dismiss the Keyboard Shortcuts screen.
*/
public final void dismissKeyboardShortcutsHelper() {
Intent intent = new Intent(Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS);
intent.setPackage(KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME);
sendBroadcastAsUser(intent, UserHandle.SYSTEM);
}
@Override
public void onProvideKeyboardShortcuts(
List<KeyboardShortcutGroup> data, Menu menu, int deviceId) {
if (menu == null) {
return;
}
KeyboardShortcutGroup group = null;
int menuSize = menu.size();
for (int i = 0; i < menuSize; ++i) {
final MenuItem item = menu.getItem(i);
final CharSequence title = item.getTitle();
final char alphaShortcut = item.getAlphabeticShortcut();
final int alphaModifiers = item.getAlphabeticModifiers();
if (title != null && alphaShortcut != MIN_VALUE) {
if (group == null) {
final int resource = mApplication.getApplicationInfo().labelRes;
group = new KeyboardShortcutGroup(resource != 0 ? getString(resource) : null);
}
group.addItem(new KeyboardShortcutInfo(
title, alphaShortcut, alphaModifiers));
}
}
if (group != null) {
data.add(group);
}
}
/**
* Ask to have the current assistant shown to the user. This only works if the calling
* activity is the current foreground activity. It is the same as calling
* {@link android.service.voice.VoiceInteractionService#showSession
* VoiceInteractionService.showSession} and requesting all of the possible context.
* The receiver will always see
* {@link android.service.voice.VoiceInteractionSession#SHOW_SOURCE_APPLICATION} set.
* @return Returns true if the assistant was successfully invoked, else false. For example
* false will be returned if the caller is not the current top activity.
*/
public boolean showAssist(Bundle args) {
try {
return ActivityManager.getService().showAssistFromActivity(mToken, args);
} catch (RemoteException e) {
}
return false;
}
/**
* Called when you are no longer visible to the user. You will next
* receive either {@link #onRestart}, {@link #onDestroy}, or nothing,
* depending on later user activity.
*
* <p><em>Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
* thrown.</em></p>
*
* @see #onRestart
* @see #onResume
* @see #onSaveInstanceState
* @see #onDestroy
*/
@CallSuper
protected void onStop() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
mActivityTransitionState.onStop();
getApplication().dispatchActivityStopped(this);
mTranslucentCallback = null;
mCalled = true;
if (mAutoFillResetNeeded) {
getAutofillManager().onInvisibleForAutofill();
}
if (isFinishing()) {
if (mAutoFillResetNeeded) {
getAutofillManager().onActivityFinishing();
} else if (mIntent != null
&& mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
// Activity was launched when user tapped a link in the Autofill Save UI - since
// user launched another activity, the Save UI should not be restored when this
// activity is finished.
getAutofillManager().onPendingSaveUi(AutofillManager.PENDING_UI_OPERATION_CANCEL,
mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN));
}
}
}
/**
* Perform any final cleanup before an activity is destroyed. This can
* happen either because the activity is finishing (someone called
* {@link #finish} on it, or because the system is temporarily destroying
* this instance of the activity to save space. You can distinguish
* between these two scenarios with the {@link #isFinishing} method.
*
* <p><em>Note: do not count on this method being called as a place for
* saving data! For example, if an activity is editing data in a content
* provider, those edits should be committed in either {@link #onPause} or
* {@link #onSaveInstanceState}, not here.</em> This method is usually implemented to
* free resources like threads that are associated with an activity, so
* that a destroyed activity does not leave such things around while the
* rest of its application is still running. There are situations where
* the system will simply kill the activity's hosting process without
* calling this method (or any others) in it, so it should not be used to
* do things that are intended to remain around after the process goes
* away.
*
* <p><em>Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
* thrown.</em></p>
*
* @see #onPause
* @see #onStop
* @see #finish
* @see #isFinishing
*/
@CallSuper
protected void onDestroy() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
mCalled = true;
// dismiss any dialogs we are managing.
if (mManagedDialogs != null) {
final int numDialogs = mManagedDialogs.size();
for (int i = 0; i < numDialogs; i++) {
final ManagedDialog md = mManagedDialogs.valueAt(i);
if (md.mDialog.isShowing()) {
md.mDialog.dismiss();
}
}
mManagedDialogs = null;
}
// close any cursors we are managing.
synchronized (mManagedCursors) {
int numCursors = mManagedCursors.size();
for (int i = 0; i < numCursors; i++) {
ManagedCursor c = mManagedCursors.get(i);
if (c != null) {
c.mCursor.close();
}
}
mManagedCursors.clear();
}
// Close any open search dialog
if (mSearchManager != null) {
mSearchManager.stopSearch();
}
if (mActionBar != null) {
mActionBar.onDestroy();
}
getApplication().dispatchActivityDestroyed(this);
}
/**
* Report to the system that your app is now fully drawn, purely for diagnostic
* purposes (calling it does not impact the visible behavior of the activity).
* This is only used to help instrument application launch times, so that the
* app can report when it is fully in a usable state; without this, the only thing
* the system itself can determine is the point at which the activity's window
* is <em>first</em> drawn and displayed. To participate in app launch time
* measurement, you should always call this method after first launch (when
* {@link #onCreate(android.os.Bundle)} is called), at the point where you have
* entirely drawn your UI and populated with all of the significant data. You
* can safely call this method any time after first launch as well, in which case
* it will simply be ignored.
*/
public void reportFullyDrawn() {
if (mDoReportFullyDrawn) {
mDoReportFullyDrawn = false;
try {
ActivityManager.getService().reportActivityFullyDrawn(mToken, mRestoredFromBundle);
} catch (RemoteException e) {
}
}
}
/**
* Called by the system when the activity changes from fullscreen mode to multi-window mode and
* visa-versa. This method provides the same configuration that will be sent in the following
* {@link #onConfigurationChanged(Configuration)} call after the activity enters this mode.
*
* @see android.R.attr#resizeableActivity
*
* @param isInMultiWindowMode True if the activity is in multi-window mode.
* @param newConfig The new configuration of the activity with the state
* {@param isInMultiWindowMode}.
*/
public void onMultiWindowModeChanged(boolean isInMultiWindowMode, Configuration newConfig) {
// Left deliberately empty. There should be no side effects if a direct
// subclass of Activity does not call super.
onMultiWindowModeChanged(isInMultiWindowMode);
}
/**
* Called by the system when the activity changes from fullscreen mode to multi-window mode and
* visa-versa.
*
* @see android.R.attr#resizeableActivity
*
* @param isInMultiWindowMode True if the activity is in multi-window mode.
*
* @deprecated Use {@link #onMultiWindowModeChanged(boolean, Configuration)} instead.
*/
@Deprecated
public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
// Left deliberately empty. There should be no side effects if a direct
// subclass of Activity does not call super.
}
/**
* Returns true if the activity is currently in multi-window mode.
* @see android.R.attr#resizeableActivity
*
* @return True if the activity is in multi-window mode.
*/
public boolean isInMultiWindowMode() {
try {
return ActivityManager.getService().isInMultiWindowMode(mToken);
} catch (RemoteException e) {
}
return false;
}
/**
* Called by the system when the activity changes to and from picture-in-picture mode. This
* method provides the same configuration that will be sent in the following
* {@link #onConfigurationChanged(Configuration)} call after the activity enters this mode.
*
* @see android.R.attr#supportsPictureInPicture
*
* @param isInPictureInPictureMode True if the activity is in picture-in-picture mode.
* @param newConfig The new configuration of the activity with the state
* {@param isInPictureInPictureMode}.
*/
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode,
Configuration newConfig) {
// Left deliberately empty. There should be no side effects if a direct
// subclass of Activity does not call super.
onPictureInPictureModeChanged(isInPictureInPictureMode);
}
/**
* Called by the system when the activity changes to and from picture-in-picture mode.
*
* @see android.R.attr#supportsPictureInPicture
*
* @param isInPictureInPictureMode True if the activity is in picture-in-picture mode.
*
* @deprecated Use {@link #onPictureInPictureModeChanged(boolean, Configuration)} instead.
*/
@Deprecated
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
// Left deliberately empty. There should be no side effects if a direct
// subclass of Activity does not call super.
}
/**
* Returns true if the activity is currently in picture-in-picture mode.
* @see android.R.attr#supportsPictureInPicture
*
* @return True if the activity is in picture-in-picture mode.
*/
public boolean isInPictureInPictureMode() {
try {
return ActivityManager.getService().isInPictureInPictureMode(mToken);
} catch (RemoteException e) {
}
return false;
}
/**
* Puts the activity in picture-in-picture mode if possible in the current system state. Any
* prior calls to {@link #setPictureInPictureParams(PictureInPictureParams)} will still apply
* when entering picture-in-picture through this call.
*
* @see #enterPictureInPictureMode(PictureInPictureParams)
* @see android.R.attr#supportsPictureInPicture
*/
@Deprecated
public void enterPictureInPictureMode() {
enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
}
/** @removed */
@Deprecated
public boolean enterPictureInPictureMode(@NonNull PictureInPictureArgs args) {
return enterPictureInPictureMode(PictureInPictureArgs.convert(args));
}
/**
* Puts the activity in picture-in-picture mode if possible in the current system state. The
* set parameters in {@param params} will be combined with the parameters from prior calls to
* {@link #setPictureInPictureParams(PictureInPictureParams)}.
*
* The system may disallow entering picture-in-picture in various cases, including when the
* activity is not visible, if the screen is locked or if the user has an activity pinned.
*
* @see android.R.attr#supportsPictureInPicture
* @see PictureInPictureParams
*
* @param params non-null parameters to be combined with previously set parameters when entering
* picture-in-picture.
*
* @return true if the system successfully put this activity into picture-in-picture mode or was
* already in picture-in-picture mode (@see {@link #isInPictureInPictureMode()). If the device
* does not support picture-in-picture, return false.
*/
public boolean enterPictureInPictureMode(@NonNull PictureInPictureParams params) {
try {
if (!deviceSupportsPictureInPictureMode()) {
return false;
}
if (params == null) {
throw new IllegalArgumentException("Expected non-null picture-in-picture params");
}
if (!mCanEnterPictureInPicture) {
throw new IllegalStateException("Activity must be resumed to enter"
+ " picture-in-picture");
}
return ActivityManagerNative.getDefault().enterPictureInPictureMode(mToken, params);
} catch (RemoteException e) {
return false;
}
}
/** @removed */
@Deprecated
public void setPictureInPictureArgs(@NonNull PictureInPictureArgs args) {
setPictureInPictureParams(PictureInPictureArgs.convert(args));
}
/**
* Updates the properties of the picture-in-picture activity, or sets it to be used later when
* {@link #enterPictureInPictureMode()} is called.
*
* @param params the new parameters for the picture-in-picture.
*/
public void setPictureInPictureParams(@NonNull PictureInPictureParams params) {
try {
if (!deviceSupportsPictureInPictureMode()) {
return;
}
if (params == null) {
throw new IllegalArgumentException("Expected non-null picture-in-picture params");
}
ActivityManagerNative.getDefault().setPictureInPictureParams(mToken, params);
} catch (RemoteException e) {
}
}
/**
* Return the number of actions that will be displayed in the picture-in-picture UI when the
* user interacts with the activity currently in picture-in-picture mode. This number may change
* if the global configuration changes (ie. if the device is plugged into an external display),
* but will always be larger than three.
*/
public int getMaxNumPictureInPictureActions() {
try {
return ActivityManagerNative.getDefault().getMaxNumPictureInPictureActions(mToken);
} catch (RemoteException e) {
return 0;
}
}
/**
* @return Whether this device supports picture-in-picture.
*/
private boolean deviceSupportsPictureInPictureMode() {
return getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE);
}
void dispatchMovedToDisplay(int displayId, Configuration config) {
updateDisplay(displayId);
onMovedToDisplay(displayId, config);
}
/**
* Called by the system when the activity is moved from one display to another without
* recreation. This means that this activity is declared to handle all changes to configuration
* that happened when it was switched to another display, so it wasn't destroyed and created
* again.
*
* <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the
* applied configuration actually changed. It is up to app developer to choose whether to handle
* the change in this method or in the following {@link #onConfigurationChanged(Configuration)}
* call.
*
* <p>Use this callback to track changes to the displays if some activity functionality relies
* on an association with some display properties.
*
* @param displayId The id of the display to which activity was moved.
* @param config Configuration of the activity resources on new display after move.
*
* @see #onConfigurationChanged(Configuration)
* @see View#onMovedToDisplay(int, Configuration)
* @hide
*/
public void onMovedToDisplay(int displayId, Configuration config) {
}
/**
* Called by the system when the device configuration changes while your
* activity is running. Note that this will <em>only</em> be called if
* you have selected configurations you would like to handle with the
* {@link android.R.attr#configChanges} attribute in your manifest. If
* any configuration change occurs that is not selected to be reported
* by that attribute, then instead of reporting it the system will stop
* and restart the activity (to have it launched with the new
* configuration).
*
* <p>At the time that this function has been called, your Resources
* object will have been updated to return resource values matching the
* new configuration.
*
* @param newConfig The new device configuration.
*/
public void onConfigurationChanged(Configuration newConfig) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onConfigurationChanged " + this + ": " + newConfig);
mCalled = true;
mFragments.dispatchConfigurationChanged(newConfig);
if (mWindow != null) {
// Pass the configuration changed event to the window
mWindow.onConfigurationChanged(newConfig);
}
if (mActionBar != null) {
// Do this last; the action bar will need to access
// view changes from above.
mActionBar.onConfigurationChanged(newConfig);
}
}
/**
* If this activity is being destroyed because it can not handle a
* configuration parameter being changed (and thus its
* {@link #onConfigurationChanged(Configuration)} method is
* <em>not</em> being called), then you can use this method to discover
* the set of changes that have occurred while in the process of being
* destroyed. Note that there is no guarantee that these will be
* accurate (other changes could have happened at any time), so you should
* only use this as an optimization hint.
*
* @return Returns a bit field of the configuration parameters that are
* changing, as defined by the {@link android.content.res.Configuration}
* class.
*/
public int getChangingConfigurations() {
return mConfigChangeFlags;
}
/**
* Retrieve the non-configuration instance data that was previously
* returned by {@link #onRetainNonConfigurationInstance()}. This will
* be available from the initial {@link #onCreate} and
* {@link #onStart} calls to the new instance, allowing you to extract
* any useful dynamic state from the previous instance.
*
* <p>Note that the data you retrieve here should <em>only</em> be used
* as an optimization for handling configuration changes. You should always
* be able to handle getting a null pointer back, and an activity must
* still be able to restore itself to its previous state (through the
* normal {@link #onSaveInstanceState(Bundle)} mechanism) even if this
* function returns null.
*
* <p><strong>Note:</strong> For most cases you should use the {@link Fragment} API
* {@link Fragment#setRetainInstance(boolean)} instead; this is also
* available on older platforms through the Android support libraries.
*
* @return the object previously returned by {@link #onRetainNonConfigurationInstance()}
*/
@Nullable
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
/**
* Called by the system, as part of destroying an
* activity due to a configuration change, when it is known that a new
* instance will immediately be created for the new configuration. You
* can return any object you like here, including the activity instance
* itself, which can later be retrieved by calling
* {@link #getLastNonConfigurationInstance()} in the new activity
* instance.
*
* <em>If you are targeting {@link android.os.Build.VERSION_CODES#HONEYCOMB}
* or later, consider instead using a {@link Fragment} with
* {@link Fragment#setRetainInstance(boolean)
* Fragment.setRetainInstance(boolean}.</em>
*
* <p>This function is called purely as an optimization, and you must
* not rely on it being called. When it is called, a number of guarantees
* will be made to help optimize configuration switching:
* <ul>
* <li> The function will be called between {@link #onStop} and
* {@link #onDestroy}.
* <li> A new instance of the activity will <em>always</em> be immediately
* created after this one's {@link #onDestroy()} is called. In particular,
* <em>no</em> messages will be dispatched during this time (when the returned
* object does not have an activity to be associated with).
* <li> The object you return here will <em>always</em> be available from
* the {@link #getLastNonConfigurationInstance()} method of the following
* activity instance as described there.
* </ul>
*
* <p>These guarantees are designed so that an activity can use this API
* to propagate extensive state from the old to new activity instance, from
* loaded bitmaps, to network connections, to evenly actively running
* threads. Note that you should <em>not</em> propagate any data that
* may change based on the configuration, including any data loaded from
* resources such as strings, layouts, or drawables.
*
* <p>The guarantee of no message handling during the switch to the next
* activity simplifies use with active objects. For example if your retained
* state is an {@link android.os.AsyncTask} you are guaranteed that its
* call back functions (like {@link android.os.AsyncTask#onPostExecute}) will
* not be called from the call here until you execute the next instance's
* {@link #onCreate(Bundle)}. (Note however that there is of course no such
* guarantee for {@link android.os.AsyncTask#doInBackground} since that is
* running in a separate thread.)
*
* <p><strong>Note:</strong> For most cases you should use the {@link Fragment} API
* {@link Fragment#setRetainInstance(boolean)} instead; this is also
* available on older platforms through the Android support libraries.
*
* @return any Object holding the desired state to propagate to the
* next activity instance
*/
public Object onRetainNonConfigurationInstance() {
return null;
}
/**
* Retrieve the non-configuration instance data that was previously
* returned by {@link #onRetainNonConfigurationChildInstances()}. This will
* be available from the initial {@link #onCreate} and
* {@link #onStart} calls to the new instance, allowing you to extract
* any useful dynamic state from the previous instance.
*
* <p>Note that the data you retrieve here should <em>only</em> be used
* as an optimization for handling configuration changes. You should always
* be able to handle getting a null pointer back, and an activity must
* still be able to restore itself to its previous state (through the
* normal {@link #onSaveInstanceState(Bundle)} mechanism) even if this
* function returns null.
*
* @return Returns the object previously returned by
* {@link #onRetainNonConfigurationChildInstances()}
*/
@Nullable
HashMap<String, Object> getLastNonConfigurationChildInstances() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.children : null;
}
/**
* This method is similar to {@link #onRetainNonConfigurationInstance()} except that
* it should return either a mapping from child activity id strings to arbitrary objects,
* or null. This method is intended to be used by Activity framework subclasses that control a
* set of child activities, such as ActivityGroup. The same guarantees and restrictions apply
* as for {@link #onRetainNonConfigurationInstance()}. The default implementation returns null.
*/
@Nullable
HashMap<String,Object> onRetainNonConfigurationChildInstances() {
return null;
}
NonConfigurationInstances retainNonConfigurationInstances() {
Object activity = onRetainNonConfigurationInstance();
HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
// We're already stopped but we've been asked to retain.
// Our fragments are taken care of but we need to mark the loaders for retention.
// In order to do this correctly we need to restart the loaders first before
// handing them off to the next activity.
mFragments.doLoaderStart();
mFragments.doLoaderStop(true);
ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();
if (activity == null && children == null && fragments == null && loaders == null
&& mVoiceInteractor == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.activity = activity;
nci.children = children;
nci.fragments = fragments;
nci.loaders = loaders;
if (mVoiceInteractor != null) {
mVoiceInteractor.retainInstance();
nci.voiceInteractor = mVoiceInteractor;
}
return nci;
}
public void onLowMemory() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onLowMemory " + this);
mCalled = true;
mFragments.dispatchLowMemory();
}
public void onTrimMemory(int level) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onTrimMemory " + this + ": " + level);
mCalled = true;
mFragments.dispatchTrimMemory(level);
}
/**
* Return the FragmentManager for interacting with fragments associated
* with this activity.
*
* @deprecated Use {@link android.support.v4.app.FragmentActivity#getSupportFragmentManager()}
*/
@Deprecated
public FragmentManager getFragmentManager() {
return mFragments.getFragmentManager();
}
/**
* Called when a Fragment is being attached to this activity, immediately
* after the call to its {@link Fragment#onAttach Fragment.onAttach()}
* method and before {@link Fragment#onCreate Fragment.onCreate()}.
*
* @deprecated Use {@link
* android.support.v4.app.FragmentActivity#onAttachFragment(android.support.v4.app.Fragment)}
*/
@Deprecated
public void onAttachFragment(Fragment fragment) {
}
/**
* Wrapper around
* {@link ContentResolver#query(android.net.Uri , String[], String, String[], String)}
* that gives the resulting {@link Cursor} to call
* {@link #startManagingCursor} so that the activity will manage its
* lifecycle for you.
*
* <em>If you are targeting {@link android.os.Build.VERSION_CODES#HONEYCOMB}
* or later, consider instead using {@link LoaderManager} instead, available
* via {@link #getLoaderManager()}.</em>
*
* <p><strong>Warning:</strong> Do not call {@link Cursor#close()} on a cursor obtained using
* this method, because the activity will do that for you at the appropriate time. However, if
* you call {@link #stopManagingCursor} on a cursor from a managed query, the system <em>will
* not</em> automatically close the cursor and, in that case, you must call
* {@link Cursor#close()}.</p>
*
* @param uri The URI of the content provider to query.
* @param projection List of columns to return.
* @param selection SQL WHERE clause.
* @param sortOrder SQL ORDER BY clause.
*
* @return The Cursor that was returned by query().
*
* @see ContentResolver#query(android.net.Uri , String[], String, String[], String)
* @see #startManagingCursor
* @hide
*
* @deprecated Use {@link CursorLoader} instead.
*/
@Deprecated
@UnsupportedAppUsage
public final Cursor managedQuery(Uri uri, String[] projection, String selection,
String sortOrder) {
Cursor c = getContentResolver().query(uri, projection, selection, null, sortOrder);
if (c != null) {
startManagingCursor(c);
}
return c;
}
/**
* Wrapper around
* {@link ContentResolver#query(android.net.Uri , String[], String, String[], String)}
* that gives the resulting {@link Cursor} to call
* {@link #startManagingCursor} so that the activity will manage its
* lifecycle for you.
*
* <em>If you are targeting {@link android.os.Build.VERSION_CODES#HONEYCOMB}
* or later, consider instead using {@link LoaderManager} instead, available
* via {@link #getLoaderManager()}.</em>
*
* <p><strong>Warning:</strong> Do not call {@link Cursor#close()} on a cursor obtained using
* this method, because the activity will do that for you at the appropriate time. However, if
* you call {@link #stopManagingCursor} on a cursor from a managed query, the system <em>will
* not</em> automatically close the cursor and, in that case, you must call
* {@link Cursor#close()}.</p>
*
* @param uri The URI of the content provider to query.
* @param projection List of columns to return.
* @param selection SQL WHERE clause.
* @param selectionArgs The arguments to selection, if any ?s are pesent
* @param sortOrder SQL ORDER BY clause.
*
* @return The Cursor that was returned by query().
*
* @see ContentResolver#query(android.net.Uri , String[], String, String[], String)
* @see #startManagingCursor
*
* @deprecated Use {@link CursorLoader} instead.
*/
@Deprecated
public final Cursor managedQuery(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
Cursor c = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);
if (c != null) {
startManagingCursor(c);
}
return c;
}
/**
* This method allows the activity to take care of managing the given
* {@link Cursor}'s lifecycle for you based on the activity's lifecycle.
* That is, when the activity is stopped it will automatically call
* {@link Cursor#deactivate} on the given Cursor, and when it is later restarted
* it will call {@link Cursor#requery} for you. When the activity is
* destroyed, all managed Cursors will be closed automatically.
*
* <em>If you are targeting {@link android.os.Build.VERSION_CODES#HONEYCOMB}
* or later, consider instead using {@link LoaderManager} instead, available
* via {@link #getLoaderManager()}.</em>
*
* <p><strong>Warning:</strong> Do not call {@link Cursor#close()} on cursor obtained from
* {@link #managedQuery}, because the activity will do that for you at the appropriate time.
* However, if you call {@link #stopManagingCursor} on a cursor from a managed query, the system
* <em>will not</em> automatically close the cursor and, in that case, you must call
* {@link Cursor#close()}.</p>
*
* @param c The Cursor to be managed.
*
* @see #managedQuery(android.net.Uri , String[], String, String[], String)
* @see #stopManagingCursor
*
* @deprecated Use the new {@link android.content.CursorLoader} class with
* {@link LoaderManager} instead; this is also
* available on older platforms through the Android compatibility package.
*/
@Deprecated
public void startManagingCursor(Cursor c) {
synchronized (mManagedCursors) {
mManagedCursors.add(new ManagedCursor(c));
}
}
/**
* Given a Cursor that was previously given to
* {@link #startManagingCursor}, stop the activity's management of that
* cursor.
*
* <p><strong>Warning:</strong> After calling this method on a cursor from a managed query,
* the system <em>will not</em> automatically close the cursor and you must call
* {@link Cursor#close()}.</p>
*
* @param c The Cursor that was being managed.
*
* @see #startManagingCursor
*
* @deprecated Use the new {@link android.content.CursorLoader} class with
* {@link LoaderManager} instead; this is also
* available on older platforms through the Android compatibility package.
*/
@Deprecated
public void stopManagingCursor(Cursor c) {
synchronized (mManagedCursors) {
final int N = mManagedCursors.size();
for (int i=0; i<N; i++) {
ManagedCursor mc = mManagedCursors.get(i);
if (mc.mCursor == c) {
mManagedCursors.remove(i);
break;
}
}
}
}
/**
* @deprecated As of {@link android.os.Build.VERSION_CODES#GINGERBREAD}
* this is a no-op.
* @hide
*/
@Deprecated
@UnsupportedAppUsage
public void setPersistent(boolean isPersistent) {
}
/**
* Finds a view that was identified by the {@code android:id} XML attribute
* that was processed in {@link #onCreate}.
* <p>
* <strong>Note:</strong> In most cases -- depending on compiler support --
* the resulting view is automatically cast to the target class type. If
* the target class type is unconstrained, an explicit cast may be
* necessary.
*
* @param id the ID to search for
* @return a view with given ID if found, or {@code null} otherwise
* @see View#findViewById(int)
* @see Activity#requireViewById(int)
*/
@Nullable
public <T extends View> T findViewById(@IdRes int id) {
return getWindow().findViewById(id);
}
/**
* Finds a view that was identified by the {@code android:id} XML attribute that was processed
* in {@link #onCreate}, or throws an IllegalArgumentException if the ID is invalid, or there is
* no matching view in the hierarchy.
* <p>
* <strong>Note:</strong> In most cases -- depending on compiler support --
* the resulting view is automatically cast to the target class type. If
* the target class type is unconstrained, an explicit cast may be
* necessary.
*
* @param id the ID to search for
* @return a view with given ID
* @see View#requireViewById(int)
* @see Activity#findViewById(int)
*/
@NonNull
public final <T extends View> T requireViewById(@IdRes int id) {
T view = findViewById(id);
if (view == null) {
throw new IllegalArgumentException("ID does not reference a View inside this Activity");
}
return view;
}
/**
* Retrieve a reference to this activity's ActionBar.
*
* @return The Activity's ActionBar, or null if it does not have one.
*/
@Nullable
public ActionBar getActionBar() {
initWindowDecorActionBar();
return mActionBar;
}
/**
* Set a {@link android.widget.Toolbar Toolbar} to act as the {@link ActionBar} for this
* Activity window.
*
* <p>When set to a non-null value the {@link #getActionBar()} method will return
* an {@link ActionBar} object that can be used to control the given toolbar as if it were
* a traditional window decor action bar. The toolbar's menu will be populated with the
* Activity's options menu and the navigation button will be wired through the standard
* {@link android.R.id#home home} menu select action.</p>
*
* <p>In order to use a Toolbar within the Activity's window content the application
* must not request the window feature {@link Window#FEATURE_ACTION_BAR FEATURE_ACTION_BAR}.</p>
*
* @param toolbar Toolbar to set as the Activity's action bar, or {@code null} to clear it
*/
public void setActionBar(@Nullable Toolbar toolbar) {
final ActionBar ab = getActionBar();
if (ab instanceof WindowDecorActionBar) {
throw new IllegalStateException("This Activity already has an action bar supplied " +
"by the window decor. Do not request Window.FEATURE_ACTION_BAR and set " +
"android:windowActionBar to false in your theme to use a Toolbar instead.");
}
// If we reach here then we're setting a new action bar
// First clear out the MenuInflater to make sure that it is valid for the new Action Bar
mMenuInflater = null;
// If we have an action bar currently, destroy it
if (ab != null) {
ab.onDestroy();
}
if (toolbar != null) {
final ToolbarActionBar tbab = new ToolbarActionBar(toolbar, getTitle(), this);
mActionBar = tbab;
mWindow.setCallback(tbab.getWrappedWindowCallback());
} else {
mActionBar = null;
// Re-set the original window callback since we may have already set a Toolbar wrapper
mWindow.setCallback(this);
}
invalidateOptionsMenu();
}
/**
* Creates a new ActionBar, locates the inflated ActionBarView,
* initializes the ActionBar with the view, and sets mActionBar.
*/
private void initWindowDecorActionBar() {
Window window = getWindow();
// Initializing the window decor can change window feature flags.
// Make sure that we have the correct set before performing the test below.
window.getDecorView();
if (isChild() || !window.hasFeature(Window.FEATURE_ACTION_BAR) || mActionBar != null) {
return;
}
mActionBar = new WindowDecorActionBar(this);
mActionBar.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp);
mWindow.setDefaultIcon(mActivityInfo.getIconResource());
mWindow.setDefaultLogo(mActivityInfo.getLogoResource());
}
/**
* Set the activity content from a layout resource. The resource will be
* inflated, adding all top-level views to the activity.
*
* @param layoutResID Resource ID to be inflated.
*
* @see #setContentView(android.view.View)
* @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
*/
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
/**
* Set the activity content to an explicit view. This view is placed
* directly into the activity's view hierarchy. It can itself be a complex
* view hierarchy. When calling this method, the layout parameters of the
* specified view are ignored. Both the width and the height of the view are
* set by default to {@link ViewGroup.LayoutParams#MATCH_PARENT}. To use
* your own layout parameters, invoke
* {@link #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}
* instead.
*
* @param view The desired content to display.
*