/** * A special variation to launch an activity only if a new activity * instance is needed to handle the given Intent. In other words, this is * just like {@link #startActivityForResult(Intent, int)} except: if you are * using the {@link Intent#FLAG_ACTIVITY_SINGLE_TOP} flag, or * singleTask or singleTop * {@link android.R.styleable#AndroidManifestActivity_launchMode launchMode}, * and the activity * that handles <var>intent</var> is the same as your currently running * activity, then a new instance is not needed. In this case, instead of * the normal behavior of calling {@link #onNewIntent} this function will * return and you can handle the Intent yourself. * * <p>This function can only be called from a top-level activity; if it is * called from a child activity, a runtime exception will be thrown. * * @param intent The intent to start. * @param requestCode If >= 0, this code will be returned in * onActivityResult() when the activity exits, as described in * {@link #startActivityForResult}. * @param options Additional options for how the Activity should be started. * See {@link android.content.Context#startActivity(Intent, Bundle) * Context.startActivity(Intent, Bundle)} for more details. * * @return If a new activity was launched then true is returned; otherwise * false is returned and you must handle the Intent yourself. * * @see #startActivity * @see #startActivityForResult */ public boolean startActivityIfNeeded(@RequiresPermission @NonNull Intent intent, int requestCode, @Nullable Bundle options) { if (mParent == null) { int result = ActivityManager.START_RETURN_INTENT_TO_CALLER; try { Uri referrer = onProvideReferrer(); if (referrer != null) { intent.putExtra(Intent.EXTRA_REFERRER, referrer); } intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(this); result = ActivityManagerNative.getDefault() .startActivity(mMainThread.getApplicationThread(), getBasePackageName(), intent, intent.resolveTypeIfNeeded(getContentResolver()), mToken, mEmbeddedID, requestCode, ActivityManager.START_FLAG_ONLY_IF_NEEDED, null, options); } catch (RemoteException e) { // Empty } Instrumentation.checkStartActivityResult(result, intent); if (requestCode >= 0) { // If this start is requesting a result, we can avoid making // the activity visible until the result is received. Setting // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the // activity hidden during this time, to avoid flickering. // This can only be done when a result is requested because // that guarantees we will get information back when the // activity is finished, no matter what happens to it. mStartedActivity = true; } return result != ActivityManager.START_RETURN_INTENT_TO_CALLER; } throw new UnsupportedOperationException( "startActivityIfNeeded can only be called from a top-level activity"); }
/** * Returns class name for this activity with the package prefix removed. * This is the default name used to read and write settings. * * @return The local class name. */ @NonNull public String getLocalClassName() { final String pkg = getPackageName(); final String cls = mComponent.getClassName(); int packageLen = pkg.length(); if (!cls.startsWith(pkg) || cls.length() <= packageLen || cls.charAt(packageLen) != '.') { return cls; } return cls.substring(packageLen+1); }
/** * This is called when a child activity of this one calls its * finishActivity(). * * @param child The activity making the call. * @param requestCode Request code that had been used to start the * activity. */ public void finishActivityFromChild(@NonNull Activity child, int requestCode) { try { ActivityManagerNative.getDefault() .finishSubActivity(mToken, child.mEmbeddedID, requestCode); } catch (RemoteException e) { // Empty } }
@Override public Object getSystemService(@ServiceName @NonNull String name) { if (getBaseContext() == null) { throw new IllegalStateException( "System services not available to Activities before onCreate()"); } if (WINDOW_SERVICE.equals(name)) { return mWindowManager; } else if (SEARCH_SERVICE.equals(name)) { ensureSearchManager(); return mSearchManager; } return super.getSystemService(name); }
/** * Create a new PendingIntent object which you can hand to others * for them to use to send result data back to your * {@link #onActivityResult} callback. The created object will be either * one-shot (becoming invalid after a result is sent back) or multiple * (allowing any number of results to be sent through it). * * @param requestCode Private request code for the sender that will be * associated with the result data when it is returned. The sender can not * modify this value, allowing you to identify incoming results. * @param data Default data to supply in the result, which may be modified * by the sender. * @param flags May be {@link PendingIntent#FLAG_ONE_SHOT PendingIntent.FLAG_ONE_SHOT}, * {@link PendingIntent#FLAG_NO_CREATE PendingIntent.FLAG_NO_CREATE}, * {@link PendingIntent#FLAG_CANCEL_CURRENT PendingIntent.FLAG_CANCEL_CURRENT}, * {@link PendingIntent#FLAG_UPDATE_CURRENT PendingIntent.FLAG_UPDATE_CURRENT}, * or any of the flags as supported by * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts * of the intent that can be supplied when the actual send happens. * * @return Returns an existing or new PendingIntent matching the given * parameters. May return null only if * {@link PendingIntent#FLAG_NO_CREATE PendingIntent.FLAG_NO_CREATE} has been * supplied. * * @see PendingIntent */ public PendingIntent createPendingResult(int requestCode, @NonNull Intent data, @PendingIntent.Flags int flags) { String packageName = getPackageName(); try { data.prepareToLeaveProcess(this); IIntentSender target = ActivityManagerNative.getDefault().getIntentSender( ActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName, mParent == null ? mToken : mParent.mToken, mEmbeddedID, requestCode, new Intent[] { data }, null, flags, null, UserHandle.myUserId()); return target != null ? new PendingIntent(target) : null; } catch (RemoteException e) { // Empty } return null; }
/** * Special version of starting an activity, for use when you are replacing * other activity components. You can use this to hand the Intent off * to the next Activity that can handle it. You typically call this in * {@link #onCreate} with the Intent returned by {@link #getIntent}. * * @param intent The intent to dispatch to the next activity. For * correct behavior, this must be the same as the Intent that started * your own activity; the only changes you can make are to the extras * inside of it. * @param options Additional options for how the Activity should be started. * See {@link android.content.Context#startActivity(Intent, Bundle) * Context.startActivity(Intent, Bundle)} for more details. * * @return Returns a boolean indicating whether there was another Activity * to start: true if there was a next activity to start, false if there * wasn't. In general, if true is returned you will then want to call * finish() on yourself. */ public boolean startNextMatchingActivity(@RequiresPermission @NonNull Intent intent, @Nullable Bundle options) { if (mParent == null) { try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(this); return ActivityManagerNative.getDefault() .startNextMatchingActivity(mToken, intent, options); } catch (RemoteException e) { // Empty } return false; } throw new UnsupportedOperationException( "startNextMatchingActivity can only be called from a top-level activity"); }
/** * Convenience for calling * {@link android.view.Window#getLayoutInflater}. */ @NonNull public LayoutInflater getLayoutInflater() { return getWindow().getLayoutInflater(); }
/** * Requests permissions to be granted to this application. These permissions * must be requested in your manifest, they should not be granted to your app, * and they should have protection level {@link android.content.pm.PermissionInfo * #PROTECTION_DANGEROUS dangerous}, regardless whether they are declared by * the platform or a third-party app. * <p> * Normal permissions {@link android.content.pm.PermissionInfo#PROTECTION_NORMAL} * are granted at install time if requested in the manifest. Signature permissions * {@link android.content.pm.PermissionInfo#PROTECTION_SIGNATURE} are granted at * install time if requested in the manifest and the signature of your app matches * the signature of the app declaring the permissions. * </p> * <p> * If your app does not have the requested permissions the user will be presented * with UI for accepting them. After the user has accepted or rejected the * requested permissions you will receive a callback on {@link * #onRequestPermissionsResult(int, String[], int[])} reporting whether the * permissions were granted or not. * </p> * <p> * Note that requesting a permission does not guarantee it will be granted and * your app should be able to run without having this permission. * </p> * <p> * This method may start an activity allowing the user to choose which permissions * to grant and which to reject. Hence, you should be prepared that your activity * may be paused and resumed. Further, granting some permissions may require * a restart of you application. In such a case, the system will recreate the * activity stack before delivering the result to {@link * #onRequestPermissionsResult(int, String[], int[])}. * </p> * <p> * When checking whether you have a permission you should use {@link * #checkSelfPermission(String)}. * </p> * <p> * Calling this API for permissions already granted to your app would show UI * to the user to decide whether the app can still hold these permissions. This * can be useful if the way your app uses data guarded by the permissions * changes significantly. * </p> * <p> * You cannot request a permission if your activity sets {@link * android.R.styleable#AndroidManifestActivity_noHistory noHistory} to * <code>true</code> because in this case the activity would not receive * result callbacks including {@link #onRequestPermissionsResult(int, String[], int[])}. * </p> * <p> * The <a href="http://developer.android.com/samples/RuntimePermissions/index.html"> * RuntimePermissions</a> sample app demonstrates how to use this method to * request permissions at run time. * </p> * * @param permissions The requested permissions. Must me non-null and not empty. * @param requestCode Application specific request code to match with a result * reported to {@link #onRequestPermissionsResult(int, String[], int[])}. * Should be >= 0. * * @see #onRequestPermissionsResult(int, String[], int[]) * @see #checkSelfPermission(String) * @see #shouldShowRequestPermissionRationale(String) */ public final void requestPermissions(@NonNull String[] permissions, int requestCode) { if (mHasCurrentPermissionsRequest) { Log.w(TAG, "Can reqeust only one set of permissions at a time"); // Dispatch the callback with empty arrays which means a cancellation. onRequestPermissionsResult(requestCode, new String[0], new int[0]); return; } Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions); startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null); mHasCurrentPermissionsRequest = true; }
/** * Enable or disable virtual reality (VR) mode for this Activity. * * <p>VR mode is a hint to Android system to switch to a mode optimized for VR applications * while this Activity has user focus.</p> * * <p>It is recommended that applications additionally declare * {@link android.R.attr#enableVrMode} in their manifest to allow for smooth activity * transitions when switching between VR activities.</p> * * <p>If the requested {@link android.service.vr.VrListenerService} component is not available, * VR mode will not be started. Developers can handle this case as follows:</p> * * <pre> * String servicePackage = "com.whatever.app"; * String serviceClass = "com.whatever.app.MyVrListenerService"; * * // Name of the component of the VrListenerService to start. * ComponentName serviceComponent = new ComponentName(servicePackage, serviceClass); * * try { * setVrModeEnabled(true, myComponentName); * } catch (PackageManager.NameNotFoundException e) { * List<ApplicationInfo> installed = getPackageManager().getInstalledApplications(0); * boolean isInstalled = false; * for (ApplicationInfo app : installed) { * if (app.packageName.equals(servicePackage)) { * isInstalled = true; * break; * } * } * if (isInstalled) { * // Package is installed, but not enabled in Settings. Let user enable it. * startActivity(new Intent(Settings.ACTION_VR_LISTENER_SETTINGS)); * } else { * // Package is not installed. Send an intent to download this. * sentIntentToLaunchAppStore(servicePackage); * } * } * </pre> * * @param enabled {@code true} to enable this mode. * @param requestedComponent the name of the component to use as a * {@link android.service.vr.VrListenerService} while VR mode is enabled. * * @throws android.content.pm.PackageManager.NameNotFoundException if the given component * to run as a {@link android.service.vr.VrListenerService} is not installed, or has * not been enabled in user settings. * * @see android.content.pm.PackageManager#FEATURE_VR_MODE * @see android.content.pm.PackageManager#FEATURE_VR_MODE_HIGH_PERFORMANCE * @see android.service.vr.VrListenerService * @see android.provider.Settings#ACTION_VR_LISTENER_SETTINGS * @see android.R.attr#enableVrMode */ public void setVrModeEnabled(boolean enabled, @NonNull ComponentName requestedComponent) throws PackageManager.NameNotFoundException { try { if (ActivityManagerNative.getDefault().setVrMode(mToken, enabled, requestedComponent) != 0) { throw new PackageManager.NameNotFoundException( requestedComponent.flattenToString()); } } catch (RemoteException e) { // pass } }