diff --git a/api/current.txt b/api/current.txt index 94f50b22b89de..77cc1f62a8fc2 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3309,6 +3309,7 @@ package android.app { method public android.view.LayoutInflater getLayoutInflater(); method public android.app.LoaderManager getLoaderManager(); method public java.lang.String getLocalClassName(); + method public final android.media.session.MediaController getMediaController(); method public android.view.MenuInflater getMenuInflater(); method public final android.app.Activity getParent(); method public android.content.Intent getParentActivityIntent(); @@ -3432,6 +3433,7 @@ package android.app { method public void setFinishOnTouchOutside(boolean); method public void setImmersive(boolean); method public void setIntent(android.content.Intent); + method public final void setMediaController(android.media.session.MediaController); method public boolean setMediaPlaying(boolean); method public final void setProgress(int); method public final void setProgressBarIndeterminate(boolean); @@ -16224,19 +16226,14 @@ package android.media.session { } public final class PlaybackState implements android.os.Parcelable { - ctor public PlaybackState(); - ctor public PlaybackState(android.media.session.PlaybackState); method public int describeContents(); method public long getActions(); method public long getBufferPosition(); method public java.lang.CharSequence getErrorMessage(); - method public float getPlaybackRate(); + method public long getLastPositionUpdateTime(); + method public float getPlaybackSpeed(); method public long getPosition(); method public int getState(); - method public void setActions(long); - method public void setBufferPosition(long); - method public void setErrorMessage(java.lang.CharSequence); - method public void setState(int, long, float); method public void writeToParcel(android.os.Parcel, int); field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L field public static final long ACTION_PAUSE = 2L; // 0x2L @@ -16263,6 +16260,17 @@ package android.media.session { field public static final int STATE_STOPPED = 1; // 0x1 } + public static final class PlaybackState.Builder { + ctor public PlaybackState.Builder(); + ctor public PlaybackState.Builder(android.media.session.PlaybackState); + method public android.media.session.PlaybackState build(); + method public android.media.session.PlaybackState.Builder setActions(long); + method public android.media.session.PlaybackState.Builder setBufferPosition(long); + method public android.media.session.PlaybackState.Builder setErrorMessage(java.lang.CharSequence); + method public android.media.session.PlaybackState.Builder setState(int, long, float, long); + method public android.media.session.PlaybackState.Builder setState(int, long, float); + } + } package android.media.tv { @@ -34285,6 +34293,7 @@ package android.view { method protected final int getForcedWindowFlags(); method public abstract android.view.LayoutInflater getLayoutInflater(); method protected final int getLocalFeatures(); + method public android.media.session.MediaController getMediaController(); method public abstract int getNavigationBarColor(); method public android.transition.Transition getSharedElementEnterTransition(); method public android.transition.Transition getSharedElementExitTransition(); @@ -34341,6 +34350,7 @@ package android.view { method public void setLayout(int, int); method public void setLocalFocus(boolean, boolean); method public void setLogo(int); + method public void setMediaController(android.media.session.MediaController); method public abstract void setNavigationBarColor(int); method public void setSharedElementEnterTransition(android.transition.Transition); method public void setSharedElementExitTransition(android.transition.Transition); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index d20a5dcf06d6a..cac646d1c32af 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -23,6 +23,7 @@ import android.transition.TransitionManager; import android.util.ArrayMap; import android.util.SuperNotCalledException; import android.widget.Toolbar; + import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.WindowDecorActionBar; import com.android.internal.app.ToolbarActionBar; @@ -51,6 +52,8 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.media.AudioManager; +import android.media.session.MediaController; +import android.media.session.MediaSession; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -109,14 +112,14 @@ import java.util.HashMap; * or embedded inside of another activity (using {@link ActivityGroup}). * * There are two methods almost all subclasses of Activity will implement: - * + * *
AndroidManifest.xml.
- *
+ *
* Topics covered here: *
An activity has essentially four states:
*
There are three key loops you may be interested in monitoring within your * activity: - * + * *
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 @@ -250,7 +253,7 @@ import java.util.HashMap; * protected void onCreate(Bundle savedInstanceState); * * protected void onStart(); - * + * * protected void onRestart(); * * protected void onResume(); @@ -366,7 +369,7 @@ import java.util.HashMap; * {@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. + * {@link #onCreate} if the activity needs to be re-created. * See the Process Lifecycle * 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 @@ -390,14 +393,14 @@ import java.util.HashMap; * * *
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.
- * + * *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 destroyed, going through the normal activity @@ -407,7 +410,7 @@ import java.util.HashMap; * 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}.
- * + * *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 @@ -415,7 +418,7 @@ import java.util.HashMap; * 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.
- * + * *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} @@ -425,7 +428,7 @@ import java.util.HashMap; * a configuration change involves any that you do not handle, however, the * activity will still be restarted and {@link #onConfigurationChanged} * will not be called.
- * + * * *When an activity exits, it can call * {@link android.app.Activity#setResult(int)} @@ -570,17 +573,17 @@ import java.util.HashMap; * * protected void onPause() { * super.onPause(); - * + * * SharedPreferences.Editor ed = mPrefs.edit(); * ed.putInt("view_mode", mCurViewMode); * ed.commit(); * } * } * - * + * * *
The ability to start a particular Activity can be enforced when it is * declared in its * manifest's {@link android.R.styleable#AndroidManifestActivity <activity>} @@ -601,10 +604,10 @@ import java.util.HashMap; * *
See the Security and Permissions * document for more information on permissions and security in general. - * + * * *
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 not propagate any data that * may change based on the configuration, including any data loaded from * resources such as strings, layouts, or drawables. - * + * *
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 @@ -1783,21 +1786,21 @@ public class Activity extends ContextThemeWrapper 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. - * + * *
Note that the data you retrieve here should only 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()}
*/
@@ -1806,7 +1809,7 @@ public class Activity extends ContextThemeWrapper
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,
@@ -1818,7 +1821,7 @@ public class Activity extends ContextThemeWrapper
HashMap
Warning: After calling this method on a cursor from a managed query, - * the system will not automatically close the cursor and you must call + * the system will not automatically close the cursor and you must call * {@link Cursor#close()}.
- * + * * @param c The Cursor that was being managed. - * + * * @see #startManagingCursor * * @deprecated Use the new {@link android.content.CursorLoader} class with @@ -2058,7 +2061,7 @@ public class Activity extends ContextThemeWrapper public View findViewById(int id) { return getWindow().findViewById(id); } - + /** * Retrieve a reference to this activity's ActionBar. * @@ -2094,7 +2097,7 @@ public class Activity extends ContextThemeWrapper mActionBar = new ToolbarActionBar(toolbar, getTitle(), this); mActionBar.invalidateOptionsMenu(); } - + /** * Creates a new ActionBar, locates the inflated ActionBarView, * initializes the ActionBar with the view, and sets mActionBar. @@ -2116,13 +2119,13 @@ public class Activity extends ContextThemeWrapper 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) */ @@ -2140,7 +2143,7 @@ public class Activity extends ContextThemeWrapper * your own layout parameters, invoke * {@link #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)} * instead. - * + * * @param view The desired content to display. * * @see #setContentView(int) @@ -2155,7 +2158,7 @@ public class Activity extends ContextThemeWrapper * 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. - * + * * @param view The desired content to display. * @param params Layout parameters for the view. * @@ -2170,7 +2173,7 @@ public class Activity extends ContextThemeWrapper /** * Add an additional content view to the activity. Added after any existing * ones in the activity -- existing views are NOT removed. - * + * * @param view The desired content to display. * @param params Layout parameters for the view. */ @@ -2235,23 +2238,23 @@ public class Activity extends ContextThemeWrapper /** * Use with {@link #setDefaultKeyMode} to turn off default handling of * keys. - * + * * @see #setDefaultKeyMode */ static public final int DEFAULT_KEYS_DISABLE = 0; /** * Use with {@link #setDefaultKeyMode} to launch the dialer during default * key handling. - * + * * @see #setDefaultKeyMode */ static public final int DEFAULT_KEYS_DIALER = 1; /** * Use with {@link #setDefaultKeyMode} to execute a menu shortcut in * default key handling. - * + * *That is, the user does not need to hold down the menu key to execute menu shortcuts. - * + * * @see #setDefaultKeyMode */ static public final int DEFAULT_KEYS_SHORTCUT = 2; @@ -2259,9 +2262,9 @@ public class Activity extends ContextThemeWrapper * Use with {@link #setDefaultKeyMode} to specify that unhandled keystrokes * will start an application-defined search. (If the application or activity does not * actually define a search, the the keys will be ignored.) - * + * *
See {@link android.app.SearchManager android.app.SearchManager} for more details. - * + * * @see #setDefaultKeyMode */ static public final int DEFAULT_KEYS_SEARCH_LOCAL = 3; @@ -2270,9 +2273,9 @@ public class Activity extends ContextThemeWrapper * Use with {@link #setDefaultKeyMode} to specify that unhandled keystrokes * will start a global search (typically web search, but some platforms may define alternate * methods for global search) - * + * *
See {@link android.app.SearchManager android.app.SearchManager} for more details. - * + * * @see #setDefaultKeyMode */ static public final int DEFAULT_KEYS_SEARCH_GLOBAL = 4; @@ -2284,16 +2287,16 @@ public class Activity extends ContextThemeWrapper * floor. Other modes allow you to launch the dialer * ({@link #DEFAULT_KEYS_DIALER}), execute a shortcut in your options * menu without requiring the menu key be held down - * ({@link #DEFAULT_KEYS_SHORTCUT}), or launch a search ({@link #DEFAULT_KEYS_SEARCH_LOCAL} + * ({@link #DEFAULT_KEYS_SHORTCUT}), or launch a search ({@link #DEFAULT_KEYS_SEARCH_LOCAL} * and {@link #DEFAULT_KEYS_SEARCH_GLOBAL}). - * + * *
Note that the mode selected here does not impact the default * handling of system keys, such as the "back" and "menu" keys, and your * activity and its views always get a first chance to receive and handle * all application keys. - * + * * @param mode The desired default key mode constant. - * + * * @see #DEFAULT_KEYS_DISABLE * @see #DEFAULT_KEYS_DIALER * @see #DEFAULT_KEYS_SHORTCUT @@ -2303,7 +2306,7 @@ public class Activity extends ContextThemeWrapper */ public final void setDefaultKeyMode(@DefaultKeyMode int mode) { mDefaultKeyMode = mode; - + // Some modes use a SpannableStringBuilder to track & dispatch input events // This list must remain in sync with the switch in onKeyDown() switch (mode) { @@ -2324,10 +2327,10 @@ public class Activity extends ContextThemeWrapper /** * Called when a key was pressed down and not handled by any of the views - * inside of the activity. So, for example, key presses while the cursor + * inside of the activity. So, for example, key presses while the cursor * is inside a TextView will not trigger the event (unless it is a navigation * to another object) because TextView handles its own key presses. - * + * *
If the focused view didn't want this event, this method is called. * *
The default implementation takes care of {@link KeyEvent#KEYCODE_BACK} @@ -2338,12 +2341,12 @@ public class Activity extends ContextThemeWrapper * will be performed; for earlier applications, it will perform the * action immediately in on-down, as those versions of the platform * behaved. - * + * *
Other additional default key handling may be performed
* if configured with {@link #setDefaultKeyMode}.
- *
+ *
* @return Return true to prevent this event from being propagated
- * further, or false to indicate that you have not handled
+ * further, or false to indicate that you have not handled
* this event and it should continue to be propagated.
* @see #onKeyUp
* @see android.view.KeyEvent
@@ -2358,11 +2361,11 @@ public class Activity extends ContextThemeWrapper
}
return true;
}
-
+
if (mDefaultKeyMode == DEFAULT_KEYS_DISABLE) {
return false;
} else if (mDefaultKeyMode == DEFAULT_KEYS_SHORTCUT) {
- if (getWindow().performPanelShortcut(Window.FEATURE_OPTIONS_PANEL,
+ if (getWindow().performPanelShortcut(Window.FEATURE_OPTIONS_PANEL,
keyCode, event, Menu.FLAG_ALWAYS_PERFORM_CLOSE)) {
return true;
}
@@ -2382,12 +2385,12 @@ public class Activity extends ContextThemeWrapper
final String str = mDefaultKeySsb.toString();
clearSpannable = true;
-
+
switch (mDefaultKeyMode) {
case DEFAULT_KEYS_DIALER:
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + str));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
+ startActivity(intent);
break;
case DEFAULT_KEYS_SEARCH_LOCAL:
startSearch(str, false, null, false);
@@ -2418,16 +2421,16 @@ public class Activity extends ContextThemeWrapper
/**
* Called when a key was released and not handled by any of the views
- * inside of the activity. So, for example, key presses while the cursor
+ * inside of the activity. So, for example, key presses while the cursor
* is inside a TextView will not trigger the event (unless it is a navigation
* to another object) because TextView handles its own key presses.
- *
+ *
*
The default implementation handles KEYCODE_BACK to stop the activity
* and go back.
- *
+ *
* @return Return true to prevent this event from being propagated
- * further, or false to indicate that you have not handled
- * this event and it should continue to be propagated.
+ * further, or false to indicate that you have not handled
+ * this event and it should continue to be propagated.
* @see #onKeyDown
* @see KeyEvent
*/
@@ -2451,7 +2454,7 @@ public class Activity extends ContextThemeWrapper
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
return false;
}
-
+
/**
* Called when the activity has detected the user's press of the back
* key. The default implementation simply finishes the current activity,
@@ -2485,9 +2488,9 @@ public class Activity extends ContextThemeWrapper
* Called when a touch screen event was not handled by any of the views
* under it. This is most useful to process touch events that happen
* outside of your window bounds, where there is no view to receive it.
- *
+ *
* @param event The touch screen event being processed.
- *
+ *
* @return Return true if you have consumed the event, false if you haven't.
* The default implementation always returns false.
*/
@@ -2496,10 +2499,10 @@ public class Activity extends ContextThemeWrapper
finish();
return true;
}
-
+
return false;
}
-
+
/**
* Called when the trackball was moved and not handled by any of the
* views inside of the activity. So, for example, if the trackball moves
@@ -2508,9 +2511,9 @@ public class Activity extends ContextThemeWrapper
* here happens before trackball movements are converted to
* DPAD key events, which then get sent back to the view hierarchy, and
* will be processed at the point for things like focus navigation.
- *
+ *
* @param event The trackball event being processed.
- *
+ *
* @return Return true if you have consumed the event, false if you haven't.
* The default implementation always returns false.
*/
@@ -2554,21 +2557,21 @@ public class Activity extends ContextThemeWrapper
* This callback and {@link #onUserLeaveHint} are intended to help
* activities manage status bar notifications intelligently; specifically,
* for helping activities determine the proper time to cancel a notfication.
- *
+ *
*
All calls to your activity's {@link #onUserLeaveHint} callback will * be accompanied by calls to {@link #onUserInteraction}. This * ensures that your activity will be told of relevant user activity such * as pulling down the notification pane and touching an item there. - * + * *
Note that this callback will be invoked for the touch down action * that begins a touch gesture, but may not be invoked for the touch-moved * and touch-up actions that follow. - * + * * @see #onUserLeaveHint() */ public void onUserInteraction() { } - + public void onWindowAttributesChanged(WindowManager.LayoutParams params) { // Update window manager if: we have a view, that view is // attached to its parent (which will be a RootView), and @@ -2589,14 +2592,14 @@ public class Activity extends ContextThemeWrapper * focus. This is the best indicator of whether this activity is visible * to the user. The default implementation clears the key tracking * state, so should always be called. - * + * *
Note that this provides information about global focus state, which * is managed independently of activity lifecycles. As such, while focus * changes will generally have some relation to lifecycle changes (an * activity that is stopped will not generally get window focus), you * should not rely on any particular order between the callbacks here and * those in the other lifecycle methods such as {@link #onResume}. - * + * *
As a general rule, however, a resumed activity will have window * focus... unless it has displayed other dialogs or popups that take * input focus, in which case the activity itself will not have focus @@ -2606,14 +2609,14 @@ public class Activity extends ContextThemeWrapper * pausing the foreground activity. * * @param hasFocus Whether the window of this activity has focus. - * + * * @see #hasWindowFocus() * @see #onResume * @see View#onWindowFocusChanged(boolean) */ public void onWindowFocusChanged(boolean hasFocus) { } - + /** * Called when the main window associated with the activity has been * attached to the window manager. @@ -2623,7 +2626,7 @@ public class Activity extends ContextThemeWrapper */ public void onAttachedToWindow() { } - + /** * Called when the main window associated with the activity has been * detached from the window manager. @@ -2633,13 +2636,13 @@ public class Activity extends ContextThemeWrapper */ public void onDetachedFromWindow() { } - + /** * Returns true if this activity's main window currently has window focus. * Note that this is not the same as the view itself having focus. - * + * * @return True if this activity's main window currently has window focus. - * + * * @see #onWindowAttributesChanged(android.view.WindowManager.LayoutParams) */ public boolean hasWindowFocus() { @@ -2661,14 +2664,14 @@ public class Activity extends ContextThemeWrapper public void onWindowDismissed() { finish(); } - + /** - * Called to process key events. You can override this to intercept all - * key events before they are dispatched to the window. Be sure to call + * Called to process key events. You can override this to intercept all + * key events before they are dispatched to the window. Be sure to call * this implementation for key events that should be handled normally. - * + * * @param event The key event. - * + * * @return boolean Return true if this event was consumed. */ public boolean dispatchKeyEvent(KeyEvent event) { @@ -2713,9 +2716,9 @@ public class Activity extends ContextThemeWrapper * intercept all touch screen events before they are dispatched to the * window. Be sure to call this implementation for touch screen events * that should be handled normally. - * + * * @param ev The touch screen event. - * + * * @return boolean Return true if this event was consumed. */ public boolean dispatchTouchEvent(MotionEvent ev) { @@ -2727,15 +2730,15 @@ public class Activity extends ContextThemeWrapper } return onTouchEvent(ev); } - + /** * Called to process trackball events. You can override this to * intercept all trackball events before they are dispatched to the * window. Be sure to call this implementation for trackball events * that should be handled normally. - * + * * @param ev The trackball event. - * + * * @return boolean Return true if this event was consumed. */ public boolean dispatchTrackballEvent(MotionEvent ev) { @@ -2830,7 +2833,7 @@ public class Activity extends ContextThemeWrapper /** * {@inheritDoc} - * + * * @return The default implementation returns true. */ public boolean onMenuOpened(int featureId, Menu menu) { @@ -2880,7 +2883,7 @@ public class Activity extends ContextThemeWrapper } } return false; - + case Window.FEATURE_CONTEXT_MENU: if(titleCondensed != null) { EventLog.writeEvent(50000, 1, titleCondensed.toString()); @@ -2894,7 +2897,7 @@ public class Activity extends ContextThemeWrapper return false; } } - + /** * Default implementation of * {@link android.view.Window.Callback#onPanelClosed(int, Menu)} for @@ -2910,7 +2913,7 @@ public class Activity extends ContextThemeWrapper mFragments.dispatchOptionsMenuClosed(menu); onOptionsMenuClosed(menu); break; - + case Window.FEATURE_CONTEXT_MENU: onContextMenuClosed(menu); break; @@ -2932,32 +2935,32 @@ public class Activity extends ContextThemeWrapper mWindow.invalidatePanelMenu(Window.FEATURE_OPTIONS_PANEL); } } - + /** * Initialize the contents of the Activity's standard options menu. You * should place your menu items in to menu. - * + * *
This is only called once, the first time the options menu is * displayed. To update the menu every time it is displayed, see * {@link #onPrepareOptionsMenu}. - * + * *
The default implementation populates the menu with standard system - * menu items. These are placed in the {@link Menu#CATEGORY_SYSTEM} group so that - * they will be correctly ordered with application-defined menu items. - * Deriving classes should always call through to the base implementation. - * + * menu items. These are placed in the {@link Menu#CATEGORY_SYSTEM} group so that + * they will be correctly ordered with application-defined menu items. + * Deriving classes should always call through to the base implementation. + * *
You can safely hold on to menu (and any items created * from it), making modifications to it as desired, until the next * time onCreateOptionsMenu() is called. - * + * *
When you add items to the menu, you can implement the Activity's * {@link #onOptionsItemSelected} method to handle them there. - * + * * @param menu The options menu in which you place your items. - * + * * @return You must return true for the menu to be displayed; * if you return false it will not be shown. - * + * * @see #onPrepareOptionsMenu * @see #onOptionsItemSelected */ @@ -2973,17 +2976,17 @@ public class Activity extends ContextThemeWrapper * called right before the menu is shown, every time it is shown. You can * use this method to efficiently enable/disable items or otherwise * dynamically modify the contents. - * + * *
The default implementation updates the system menu items based on the * activity's state. Deriving classes should always call through to the * base class implementation. - * + * * @param menu The options menu as last shown or first initialized by * onCreateOptionsMenu(). - * + * * @return You must return true for the menu to be displayed; * if you return false it will not be shown. - * + * * @see #onCreateOptionsMenu */ public boolean onPrepareOptionsMenu(Menu menu) { @@ -3000,15 +3003,15 @@ public class Activity extends ContextThemeWrapper * its Handler as appropriate). You can use this method for any items * for which you would like to do processing without those other * facilities. - * + * *
Derived classes should call through to the base class for it to * perform the default menu handling.
- * + * * @param item The menu item that was selected. - * + * * @return boolean Return false to allow normal menu processing to * proceed, true to consume it here. - * + * * @see #onCreateOptionsMenu */ public boolean onOptionsItemSelected(MenuItem item) { @@ -3125,7 +3128,7 @@ public class Activity extends ContextThemeWrapper /** * This hook is called whenever the options menu is being closed (either by the user canceling * the menu with the back/menu button, or when an item is selected). - * + * * @param menu The options menu as last shown or first initialized by * onCreateOptionsMenu(). */ @@ -3134,7 +3137,7 @@ public class Activity extends ContextThemeWrapper mParent.onOptionsMenuClosed(menu); } } - + /** * Programmatically opens the options menu. If the options menu is already * open, this method does nothing. @@ -3144,7 +3147,7 @@ public class Activity extends ContextThemeWrapper mWindow.openPanel(Window.FEATURE_OPTIONS_PANEL, null); } } - + /** * Progammatically closes the options menu. If the options menu is already * closed, this method does nothing. @@ -3175,43 +3178,43 @@ public class Activity extends ContextThemeWrapper * {@link OnCreateContextMenuListener} on the view to this activity, so * {@link #onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} will be * called when it is time to show the context menu. - * + * * @see #unregisterForContextMenu(View) * @param view The view that should show a context menu. */ public void registerForContextMenu(View view) { view.setOnCreateContextMenuListener(this); } - + /** * Prevents a context menu to be shown for the given view. This method will remove the * {@link OnCreateContextMenuListener} on the view. - * + * * @see #registerForContextMenu(View) * @param view The view that should stop showing a context menu. */ public void unregisterForContextMenu(View view) { view.setOnCreateContextMenuListener(null); } - + /** * Programmatically opens the context menu for a particular {@code view}. * The {@code view} should have been added via * {@link #registerForContextMenu(View)}. - * + * * @param view The view to show the context menu for. */ public void openContextMenu(View view) { view.showContextMenu(); } - + /** * Programmatically closes the most recently opened context menu, if showing. */ public void closeContextMenu() { mWindow.closePanel(Window.FEATURE_CONTEXT_MENU); } - + /** * This hook is called whenever an item in a context menu is selected. The * default implementation simply returns false to have the normal processing @@ -3224,7 +3227,7 @@ public class Activity extends ContextThemeWrapper ** Derived classes should call through to the base class for it to perform * the default menu handling. - * + * * @param item The context menu item that was selected. * @return boolean Return false to allow normal context menu processing to * proceed, true to consume it here. @@ -3240,7 +3243,7 @@ public class Activity extends ContextThemeWrapper * This hook is called whenever the context menu is being closed (either by * the user canceling the menu with the back/menu button, or when an item is * selected). - * + * * @param menu The context menu that is being closed. */ public void onContextMenuClosed(Menu menu) { @@ -3309,14 +3312,14 @@ public class Activity extends ContextThemeWrapper * Provides an opportunity to prepare a managed dialog before it is being * shown. The default implementation calls through to * {@link #onPrepareDialog(int, Dialog)} for compatibility. - * + * *
* Override this if you need to update a managed dialog based on the state * of the application each time it is shown. For example, a time picker * dialog might want to be updated with the current time. You should call * through to the superclass's implementation. The default implementation * will set this Activity as the owner activity on the Dialog. - * + * * @param id The id of the managed dialog. * @param dialog The dialog. * @param args The dialog arguments provided to {@link #showDialog(int, Bundle)}. @@ -3367,7 +3370,7 @@ public class Activity extends ContextThemeWrapper * If you need to rebuild the dialog, call {@link #removeDialog(int)} first. * @return Returns true if the Dialog was created; false is returned if * it is not created because {@link #onCreateDialog(int, Bundle)} returns false. - * + * * @see Dialog * @see #onCreateDialog(int, Bundle) * @see #onPrepareDialog(int, Dialog, Bundle) @@ -3393,7 +3396,7 @@ public class Activity extends ContextThemeWrapper } mManagedDialogs.put(id, md); } - + md.mArgs = args; onPrepareDialog(id, md.mDialog, args); md.mDialog.show(); @@ -3422,7 +3425,7 @@ public class Activity extends ContextThemeWrapper if (mManagedDialogs == null) { throw missingDialog(id); } - + final ManagedDialog md = mManagedDialogs.get(id); if (md == null) { throw missingDialog(id); @@ -3449,7 +3452,7 @@ public class Activity extends ContextThemeWrapper *
As of {@link android.os.Build.VERSION_CODES#GINGERBREAD}, this function * will not throw an exception if you try to remove an ID that does not * currently have an associated dialog.
- * + * * @param id The id of the managed dialog. * * @see #onCreateDialog(int, Bundle) @@ -3474,37 +3477,37 @@ public class Activity extends ContextThemeWrapper /** * This hook is called when the user signals the desire to start a search. - * + * *You can use this function as a simple way to launch the search UI, in response to a - * menu item, search button, or other widgets within your activity. Unless overidden, + * menu item, search button, or other widgets within your activity. Unless overidden, * calling this function is the same as calling * {@link #startSearch startSearch(null, false, null, false)}, which launches * search for the current activity as specified in its manifest, see {@link SearchManager}. - * + * *
You can override this function to force global search, e.g. in response to a dedicated * search key, or to block search entirely (by simply returning false). - * + * * @return Returns {@code true} if search launched, and {@code false} if activity blocks it. * The default implementation always returns {@code true}. - * + * * @see android.app.SearchManager */ public boolean onSearchRequested() { - startSearch(null, false, null, false); + startSearch(null, false, null, false); return true; } - + /** * This hook is called to launch the search UI. - * - *
It is typically called from onSearchRequested(), either directly from - * Activity.onSearchRequested() or from an overridden version in any given + * + *
It is typically called from onSearchRequested(), either directly from + * Activity.onSearchRequested() or from an overridden version in any given * Activity. If your goal is simply to activate search, it is preferred to call * onSearchRequested(), which may have been overridden elsewhere in your Activity. If your goal * is to inject specific data such as context data, it is preferred to override * onSearchRequested(), so that any callers to it will benefit from the override. - * - * @param initialQuery Any non-null non-empty string will be inserted as + * + * @param initialQuery Any non-null non-empty string will be inserted as * pre-entered text in the search query box. * @param selectInitialQuery If true, the initial query will be preselected, which means that * any further typing will replace it. This is useful for cases where an entire pre-formed @@ -3512,15 +3515,15 @@ public class Activity extends ContextThemeWrapper * inserted query. This is useful when the inserted query is text that the user entered, * and the user would expect to be able to keep typing. This parameter is only meaningful * if initialQuery is a non-empty string. - * @param appSearchData An application can insert application-specific - * context here, in order to improve quality or specificity of its own + * @param appSearchData An application can insert application-specific + * context here, in order to improve quality or specificity of its own * searches. This data will be returned with SEARCH intent(s). Null if * no extra data is required. * @param globalSearch If false, this will only launch the search that has been specifically - * defined by the application (which is usually defined as a local search). If no default + * defined by the application (which is usually defined as a local search). If no default * search is defined in the current application or activity, global search will be launched. * If true, this will always launch a platform-global (e.g. web-based) search instead. - * + * * @see android.app.SearchManager * @see #onSearchRequested */ @@ -3528,7 +3531,7 @@ public class Activity extends ContextThemeWrapper @Nullable Bundle appSearchData, boolean globalSearch) { ensureSearchManager(); mSearchManager.startSearch(initialQuery, selectInitialQuery, getComponentName(), - appSearchData, globalSearch); + appSearchData, globalSearch); } /** @@ -3550,7 +3553,7 @@ public class Activity extends ContextThemeWrapper * Request that key events come to this activity. Use this if your * activity has no views with focus, but the activity still wants * a chance to process key events. - * + * * @see android.view.Window#takeKeyEvents */ public void takeKeyEvents(boolean get) { @@ -3560,12 +3563,12 @@ public class Activity extends ContextThemeWrapper /** * Enable extended window features. This is a convenience for calling * {@link android.view.Window#requestFeature getWindow().requestFeature()}. - * + * * @param featureId The desired feature as defined in * {@link android.view.Window}. * @return Returns true if the requested feature is supported and now * enabled. - * + * * @see android.view.Window#requestFeature */ public final boolean requestWindowFeature(int featureId) { @@ -3677,7 +3680,7 @@ public class Activity extends ContextThemeWrapper * Launch an activity for which you would like a result when it finished. * When this activity exits, your * onActivityResult() method will be called with the given requestCode. - * Using a negative requestCode is the same as calling + * Using a negative requestCode is the same as calling * {@link #startActivity} (the activity is not launched as a sub-activity). * *
Note that this method should only be used with Intent protocols @@ -3687,7 +3690,7 @@ public class Activity extends ContextThemeWrapper * are launching uses the singleTask launch mode, it will not run in your * task and thus you will immediately receive a cancel result. * - *
As a special case, if you call startActivityForResult() with a requestCode + *
As a special case, if you call startActivityForResult() with a requestCode * >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your * activity, then your window will not be displayed until a result is * returned back from the started activity. This is to avoid visible @@ -3845,7 +3848,7 @@ public class Activity extends ContextThemeWrapper * here; otherwise, its associated action will be executed (such as * sending a broadcast) as if you had called * {@link IntentSender#sendIntent IntentSender.sendIntent} on it. - * + * * @param intent The IntentSender to launch. * @param requestCode If >= 0, this code will be returned in * onActivityResult() when the activity exits. @@ -3936,19 +3939,19 @@ public class Activity extends ContextThemeWrapper * information, the {@link Intent#FLAG_ACTIVITY_NEW_TASK} launch flag is not * required; if not specified, the new activity will be added to the * task of the caller. - * + * *
This method throws {@link android.content.ActivityNotFoundException} * if there was no Activity found to run the given Intent. - * - * @param intent The intent to start. + * + * @param intent The intent to start. * @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. - * + * * @throws android.content.ActivityNotFoundException * * @see {@link #startActivity(Intent)} - * @see #startActivityForResult + * @see #startActivityForResult */ @Override public void startActivity(Intent intent, @Nullable Bundle options) { @@ -4008,7 +4011,7 @@ public class Activity extends ContextThemeWrapper /** * Same as calling {@link #startIntentSender(IntentSender, Intent, int, int, int, Bundle)} * with no options. - * + * * @param intent The IntentSender to launch. * @param fillInIntent If non-null, this will be provided as the * intent parameter to {@link IntentSender#sendIntent}. @@ -4081,19 +4084,19 @@ public class Activity extends ContextThemeWrapper /** * 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 + * just like {@link #startActivityForResult(Intent, int)} except: if you are * using the {@link Intent#FLAG_ACTIVITY_SINGLE_TOP} flag, or - * singleTask or singleTop + * singleTask or singleTop * {@link android.R.styleable#AndroidManifestActivity_launchMode launchMode}, - * and the activity - * that handles intent 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. - * + * and the activity + * that handles intent 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. + * *
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 @@ -4101,10 +4104,10 @@ public class Activity extends ContextThemeWrapper * @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 */ @@ -4167,7 +4170,7 @@ public class Activity extends ContextThemeWrapper * 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 @@ -4175,7 +4178,7 @@ public class Activity extends ContextThemeWrapper * @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 @@ -4217,23 +4220,23 @@ public class Activity extends ContextThemeWrapper } /** - * This is called when a child activity of this one calls its + * This is called when a child activity of this one calls its * {@link #startActivity} or {@link #startActivityForResult} method. - * + * *
This method throws {@link android.content.ActivityNotFoundException} * if there was no Activity found to run the given Intent. - * + * * @param child The activity making the call. * @param intent The intent to start. * @param requestCode Reply request code. < 0 if reply is not requested. * @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. - * + * * @throws android.content.ActivityNotFoundException - * - * @see #startActivity - * @see #startActivityForResult + * + * @see #startActivity + * @see #startActivityForResult */ public void startActivityFromChild(@NonNull Activity child, Intent intent, int requestCode, @Nullable Bundle options) { @@ -4267,24 +4270,24 @@ public class Activity extends ContextThemeWrapper } /** - * This is called when a Fragment in this activity calls its + * This is called when a Fragment in this activity calls its * {@link Fragment#startActivity} or {@link Fragment#startActivityForResult} * method. - * + * *
This method throws {@link android.content.ActivityNotFoundException} * if there was no Activity found to run the given Intent. - * + * * @param fragment The fragment making the call. * @param intent The intent to start. - * @param requestCode Reply request code. < 0 if reply is not requested. + * @param requestCode Reply request code. < 0 if reply is not requested. * @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. - * + * * @throws android.content.ActivityNotFoundException - * - * @see Fragment#startActivity - * @see Fragment#startActivityForResult + * + * @see Fragment#startActivity + * @see Fragment#startActivityForResult */ public void startActivityFromFragment(@NonNull Fragment fragment, Intent intent, int requestCode, @Nullable Bundle options) { @@ -4352,14 +4355,14 @@ public class Activity extends ContextThemeWrapper } catch (RemoteException e) { } } - + /** * Call this to set the result that your activity will return to its * caller. - * + * * @param resultCode The result code to propagate back to the originating * activity, often RESULT_CANCELED or RESULT_OK - * + * * @see #RESULT_CANCELED * @see #RESULT_OK * @see #RESULT_FIRST_USER @@ -4388,7 +4391,7 @@ public class Activity extends ContextThemeWrapper * @param resultCode The result code to propagate back to the originating * activity, often RESULT_CANCELED or RESULT_OK * @param data The data to propagate back to the originating activity. - * + * * @see #RESULT_CANCELED * @see #RESULT_OK * @see #RESULT_FIRST_USER @@ -4406,10 +4409,10 @@ public class Activity extends ContextThemeWrapper * the data in {@link #setResult setResult()} will be sent to. You can * use this information to validate that the recipient is allowed to * receive the data. - * + * *
Note: if the calling activity is not expecting a result (that is it - * did not use the {@link #startActivityForResult} - * form that includes a request code), then the calling package will be + * did not use the {@link #startActivityForResult} + * form that includes a request code), then the calling package will be * null.
* *Note: prior to {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, @@ -4417,7 +4420,7 @@ public class Activity extends ContextThemeWrapper * package was no longer running, it would return null instead of the proper package * name. You can use {@link #getCallingActivity()} and retrieve the package name * from that instead.
- * + * * @return The package of the activity that will receive your * reply, or null if none. */ @@ -4435,12 +4438,12 @@ public class Activity extends ContextThemeWrapper * who the data in {@link #setResult setResult()} will be sent to. You * can use this information to validate that the recipient is allowed to * receive the data. - * + * *Note: if the calling activity is not expecting a result (that is it - * did not use the {@link #startActivityForResult} - * form that includes a request code), then the calling package will be - * null. - * + * did not use the {@link #startActivityForResult} + * form that includes a request code), then the calling package will be + * null. + * * @return The ComponentName of the activity that will receive your * reply, or null if none. */ @@ -4459,7 +4462,7 @@ public class Activity extends ContextThemeWrapper * UI itself, but can't just finish prior to onResume() because it needs * to wait for a service binding or such. Setting this to false allows * you to prevent your UI from being shown during that time. - * + * *
The default value for this is taken from the * {@link android.R.attr#windowNoDisplay} attribute of the activity's theme. */ @@ -4472,7 +4475,7 @@ public class Activity extends ContextThemeWrapper } } } - + void makeVisible() { if (!mWindowAdded) { ViewManager wm = getWindowManager(); @@ -4481,16 +4484,16 @@ public class Activity extends ContextThemeWrapper } mDecor.setVisibility(View.VISIBLE); } - + /** * Check to see whether this activity is in the process of finishing, * either because you called {@link #finish} on it or someone else * has requested that it finished. This is often used in * {@link #onPause} to determine whether the activity is simply pausing or * completely finishing. - * + * * @return If the activity is finishing, returns true; else returns false. - * + * * @see #finish */ public boolean isFinishing() { @@ -4510,7 +4513,7 @@ public class Activity extends ContextThemeWrapper * recreated with a new configuration. This is often used in * {@link #onStop} to determine whether the state needs to be cleaned up or will be passed * on to the next instance of the activity via {@link #onRetainNonConfigurationInstance()}. - * + * * @return If the activity is being torn down in order to be recreated with a new configuration, * returns true; else returns false. */ @@ -4603,12 +4606,12 @@ public class Activity extends ContextThemeWrapper } /** - * This is called when a child activity of this one calls its + * This is called when a child activity of this one calls its * {@link #finish} method. The default implementation simply calls * finish() on this activity (the parent), finishing the entire group. - * + * * @param child The activity making the call. - * + * * @see #finish */ public void finishFromChild(Activity child) { @@ -4631,7 +4634,7 @@ public class Activity extends ContextThemeWrapper /** * Force finish another activity that you had previously started with * {@link #startActivityForResult}. - * + * * @param requestCode The request code of the activity that you had * given to startActivityForResult(). If there are multiple * activities started with this request code, they @@ -4653,7 +4656,7 @@ public class Activity extends ContextThemeWrapper /** * 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. @@ -4681,10 +4684,10 @@ public class Activity extends ContextThemeWrapper * data from it. The resultCode will be * {@link #RESULT_CANCELED} if the activity explicitly returned that, * didn't return any result, or crashed during its operation. - * + * *
You will receive this call immediately before onResume() when your * activity is re-starting. - * + * * @param requestCode The integer request code originally supplied to * startActivityForResult(), allowing you to identify who this * result came from. @@ -4692,7 +4695,7 @@ public class Activity extends ContextThemeWrapper * through its setResult(). * @param data An Intent, which can return result data to the caller * (various data can be attached to Intent "extras"). - * + * * @see #startActivityForResult * @see #createPendingResult * @see #setResult(int) @@ -4722,12 +4725,12 @@ public class Activity extends ContextThemeWrapper } /** - * 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). - * + * 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. @@ -4740,12 +4743,12 @@ public class Activity extends ContextThemeWrapper * 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, @@ -4772,7 +4775,7 @@ public class Activity extends ContextThemeWrapper * orientation, the screen will immediately be changed (possibly causing * the activity to be restarted). Otherwise, this will be used the next * time the activity is visible. - * + * * @param requestedOrientation An orientation constant as used in * {@link ActivityInfo#screenOrientation ActivityInfo.screenOrientation}. */ @@ -4788,13 +4791,13 @@ public class Activity extends ContextThemeWrapper mParent.setRequestedOrientation(requestedOrientation); } } - + /** * Return the current requested orientation of the activity. This will * either be the orientation requested in its component's manifest, or * the last requested orientation given to * {@link #setRequestedOrientation(int)}. - * + * * @return Returns an orientation constant as used in * {@link ActivityInfo#screenOrientation ActivityInfo.screenOrientation}. */ @@ -4812,11 +4815,11 @@ public class Activity extends ContextThemeWrapper } return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } - + /** * Return the identifier of the task this activity is in. This identifier * will remain the same for the lifetime of the activity. - * + * * @return Task identifier, an opaque integer. */ public int getTaskId() { @@ -4831,7 +4834,7 @@ public class Activity extends ContextThemeWrapper /** * Return whether this activity is the root of a task. The root is the * first activity in a task. - * + * * @return True if this is the root activity, else false. */ public boolean isTaskRoot() { @@ -4846,11 +4849,11 @@ public class Activity extends ContextThemeWrapper /** * Move the task containing this activity to the back of the activity * stack. The activity's order within the task is unchanged. - * + * * @param nonRoot If false then this only works if the activity is the root * of a task; if true it will work for any activity in * a task. - * + * * @return If the task was moved (or it was already at the * back) true is returned, else false. */ @@ -4867,7 +4870,7 @@ public class Activity extends ContextThemeWrapper /** * 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 @@ -4881,10 +4884,10 @@ public class Activity extends ContextThemeWrapper } return cls.substring(packageLen+1); } - + /** * Returns complete component name of this activity. - * + * * @return Returns the complete component name for this activity */ public ComponentName getComponentName() @@ -4897,9 +4900,9 @@ public class Activity extends ContextThemeWrapper * that are private to this activity. This simply calls the underlying * {@link #getSharedPreferences(String, int)} method by passing in this activity's * class name as the preferences name. - * - * @param mode Operating mode. Use {@link #MODE_PRIVATE} for the default - * operation, {@link #MODE_WORLD_READABLE} and + * + * @param mode Operating mode. Use {@link #MODE_PRIVATE} for the default + * operation, {@link #MODE_WORLD_READABLE} and * {@link #MODE_WORLD_WRITEABLE} to control permissions. * * @return Returns the single SharedPreferences instance that can be used @@ -4908,12 +4911,12 @@ public class Activity extends ContextThemeWrapper public SharedPreferences getPreferences(int mode) { return getSharedPreferences(getLocalClassName(), mode); } - + private void ensureSearchManager() { if (mSearchManager != null) { return; } - + mSearchManager = new SearchManager(this, null); } @@ -5031,7 +5034,7 @@ public class Activity extends ContextThemeWrapper *
* In order for the progress bar to be shown, the feature must be requested * via {@link #requestWindowFeature(int)}. - * + * * @param visible Whether to show the progress bars in the title. */ public final void setProgressBarVisibility(boolean visible) { @@ -5051,14 +5054,14 @@ public class Activity extends ContextThemeWrapper getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS, visible ? Window.PROGRESS_VISIBILITY_ON : Window.PROGRESS_VISIBILITY_OFF); } - + /** * Sets whether the horizontal progress bar in the title should be indeterminate (the circular * is always indeterminate). *
* In order for the progress bar to be shown, the feature must be requested * via {@link #requestWindowFeature(int)}. - * + * * @param indeterminate Whether the horizontal progress bar should be indeterminate. */ public final void setProgressBarIndeterminate(boolean indeterminate) { @@ -5066,13 +5069,13 @@ public class Activity extends ContextThemeWrapper indeterminate ? Window.PROGRESS_INDETERMINATE_ON : Window.PROGRESS_INDETERMINATE_OFF); } - + /** * Sets the progress for the progress bars in the title. *
* In order for the progress bar to be shown, the feature must be requested * via {@link #requestWindowFeature(int)}. - * + * * @param progress The progress for the progress bar. Valid ranges are from * 0 to 10000 (both inclusive). If 10000 is given, the progress * bar will be completely filled and will fade out. @@ -5080,7 +5083,7 @@ public class Activity extends ContextThemeWrapper public final void setProgress(int progress) { getWindow().setFeatureInt(Window.FEATURE_PROGRESS, progress + Window.PROGRESS_START); } - + /** * Sets the secondary progress for the progress bar in the title. This * progress is drawn between the primary progress (set via @@ -5090,7 +5093,7 @@ public class Activity extends ContextThemeWrapper *
* In order for the progress bar to be shown, the feature must be requested * via {@link #requestWindowFeature(int)}. - * + * * @param secondaryProgress The secondary progress for the progress bar. Valid ranges are from * 0 to 10000 (both inclusive). */ @@ -5104,16 +5107,16 @@ public class Activity extends ContextThemeWrapper * volume controls. *
* The suggested audio stream will be tied to the window of this Activity. - * If the Activity is switched, the stream set here is no longer the - * suggested stream. The client does not need to save and restore the old - * suggested stream value in onPause and onResume. - * + * Volume requests which are received while the Activity is in the + * foreground will affect this stream. + *
+ * It is not guaranteed that the hardware volume controls will always change + * this stream's volume (for example, if a call is in progress, its stream's + * volume may be changed instead). To reset back to the default, use + * {@link AudioManager#USE_DEFAULT_STREAM_TYPE}. + * * @param streamType The type of the audio stream whose volume should be - * changed by the hardware volume controls. It is not guaranteed that - * the hardware volume controls will always change this stream's - * volume (for example, if a call is in progress, its stream's volume - * may be changed instead). To reset back to the default, use - * {@link AudioManager#USE_DEFAULT_STREAM_TYPE}. + * changed by the hardware volume controls. */ public final void setVolumeControlStream(int streamType) { getWindow().setVolumeControlStream(streamType); @@ -5122,7 +5125,7 @@ public class Activity extends ContextThemeWrapper /** * Gets the suggested audio stream whose volume should be changed by the * hardware volume controls. - * + * * @return The suggested audio stream type whose volume should be changed by * the hardware volume controls. * @see #setVolumeControlStream(int) @@ -5130,7 +5133,40 @@ public class Activity extends ContextThemeWrapper public final int getVolumeControlStream() { return getWindow().getVolumeControlStream(); } - + + /** + * Sets a {@link MediaController} to send media keys and volume changes to. + *
+ * The controller will be tied to the window of this Activity. Media key and + * volume events which are received while the Activity is in the foreground + * will be forwarded to the controller and used to invoke transport controls + * or adjust the volume. This may be used instead of or in addition to + * {@link #setVolumeControlStream} to affect a specific session instead of a + * specific stream. + *
+ * It is not guaranteed that the hardware volume controls will always change
+ * this session's volume (for example, if a call is in progress, its
+ * stream's volume may be changed instead). To reset back to the default use
+ * null as the controller.
+ *
+ * @param controller The controller for the session which should receive
+ * media keys and volume changes.
+ */
+ public final void setMediaController(MediaController controller) {
+ getWindow().setMediaController(controller);
+ }
+
+ /**
+ * Gets the controller which should be receiving media key and volume events
+ * while this activity is in the foreground.
+ *
+ * @return The controller which should receive events.
+ * @see #setMediaController(android.media.session.MediaController)
+ */
+ public final MediaController getMediaController() {
+ return getWindow().getMediaController();
+ }
+
/**
* Runs the specified action on the UI thread. If the current thread is the UI
* thread, then the action is executed immediately. If the current thread is
@@ -5176,7 +5212,7 @@ public class Activity extends ContextThemeWrapper
if (!"fragment".equals(name)) {
return onCreateView(name, context, attrs);
}
-
+
return mFragments.onCreateView(parent, name, context, attrs);
}
@@ -5737,7 +5773,7 @@ public class Activity extends ContextThemeWrapper
}
// ------------------ Internal API ------------------
-
+
final void setParent(Activity parent) {
mParent = parent;
}
@@ -5751,7 +5787,7 @@ public class Activity extends ContextThemeWrapper
attachBaseContext(context);
mFragments.attachActivity(this, mContainer, null);
-
+
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
@@ -5846,7 +5882,7 @@ public class Activity extends ContextThemeWrapper
}
mActivityTransitionState.enterReady(this);
}
-
+
final void performRestart() {
mFragments.noteStateNotSaved();
@@ -5885,14 +5921,14 @@ public class Activity extends ContextThemeWrapper
performStart();
}
}
-
+
final void performResume() {
performRestart();
-
+
mFragments.execPendingActions();
-
+
mLastNonConfigurationInstances = null;
-
+
mCalled = false;
// mResumed is set by the instrumentation
mInstrumentation.callActivityOnResume(this);
@@ -5904,10 +5940,10 @@ public class Activity extends ContextThemeWrapper
// Now really resume, and install the current status bar and menu.
mCalled = false;
-
+
mFragments.dispatchResume();
mFragments.execPendingActions();
-
+
onPostResume();
if (!mCalled) {
throw new SuperNotCalledException(
@@ -5930,12 +5966,12 @@ public class Activity extends ContextThemeWrapper
}
mResumed = false;
}
-
+
final void performUserLeaving() {
onUserInteraction();
onUserLeaveHint();
}
-
+
final void performStop() {
mDoReportFullyDrawn = false;
if (mLoadersStarted) {
@@ -5948,7 +5984,7 @@ public class Activity extends ContextThemeWrapper
}
}
}
-
+
if (!mStopped) {
if (mWindow != null) {
mWindow.closeAllPanels();
@@ -5957,9 +5993,9 @@ public class Activity extends ContextThemeWrapper
if (mToken != null && mParent == null) {
WindowManagerGlobal.getInstance().setStoppedState(mToken, true);
}
-
+
mFragments.dispatchStop();
-
+
mCalled = false;
mInstrumentation.callActivityOnStop(this);
if (!mCalled) {
@@ -5967,7 +6003,7 @@ public class Activity extends ContextThemeWrapper
"Activity " + mComponent.toShortString() +
" did not call through to super.onStop()");
}
-
+
synchronized (mManagedCursors) {
final int N = mManagedCursors.size();
for (int i=0; i Note that calling this function for the first time "locks in"
* various window characteristics as described in
* {@link #setContentView(View, android.view.ViewGroup.LayoutParams)}.
- * The position must be in ms and indicates the current playback position
- * within the track. If the position is unknown use
- * {@link #PLAYBACK_POSITION_UNKNOWN}.
- *
- * The rate is a multiple of normal playback and should be 0 when paused and
- * negative when rewinding. Normal playback rate is 1.0.
- *
- * The state must be one of the following:
- *
+ * The position must be in ms and indicates the current playback
+ * position within the track. If the position is unknown use
+ * {@link #PLAYBACK_POSITION_UNKNOWN}. When not using an unknown
+ * position the time at which the position was updated must be provided.
+ * It is okay to use {@link SystemClock#elapsedRealtime()} if the
+ * current position was just retrieved.
+ *
+ * The speed is a multiple of normal playback and should be 0 when
+ * paused and negative when rewinding. Normal playback speed is 1.0.
+ *
+ * The state must be one of the following:
+ *
+ * The position must be in ms and indicates the current playback
+ * position within the track. If the position is unknown use
+ * {@link #PLAYBACK_POSITION_UNKNOWN}. The update time will be set to
+ * the current {@link SystemClock#elapsedRealtime()}.
+ *
+ * The speed is a multiple of normal playback and should be 0 when
+ * paused and negative when rewinding. Normal playback speed is 1.0.
+ *
+ * The state must be one of the following:
+ *
- *
- *
- * @param state The current state of playback.
- * @param position The position in the current track in ms.
- * @param playbackRate The current rate of playback as a multiple of normal
- * playback.
- */
- public void setState(int state, long position, float playbackRate) {
- this.mState = state;
- this.mPosition = position;
- this.mRate = playbackRate;
- mUpdateTime = SystemClock.elapsedRealtime();
- }
-
/**
* Get the current playback position in ms.
*/
@@ -323,23 +276,14 @@ public final class PlaybackState implements Parcelable {
}
/**
- * Set the current buffer position in ms. This is the farthest playback
- * point that can be reached from the current position using only buffered
- * content.
- */
- public void setBufferPosition(long bufferPosition) {
- mBufferPosition = bufferPosition;
- }
-
- /**
- * Get the current playback rate as a multiple of normal playback. This
+ * Get the current playback speed as a multiple of normal playback. This
* should be negative when rewinding. A value of 1 means normal playback and
* 0 means paused.
*
- * @return The current rate of playback.
+ * @return The current speed of playback.
*/
- public float getPlaybackRate() {
- return mRate;
+ public float getPlaybackSpeed() {
+ return mSpeed;
}
/**
@@ -361,25 +305,6 @@ public final class PlaybackState implements Parcelable {
return mActions;
}
- /**
- * Set the current capabilities available on this session. This should use a
- * bitmask of the available capabilities.
- *
- *
- */
- public void setActions(long capabilities) {
- mActions = capabilities;
- }
-
/**
* Get a user readable error message. This should be set when the state is
* {@link PlaybackState#STATE_ERROR}.
@@ -393,20 +318,11 @@ public final class PlaybackState implements Parcelable {
* position has never been set this will return 0;
*
* @return The last time the position was updated.
- * @hide
*/
public long getLastPositionUpdateTime() {
return mUpdateTime;
}
- /**
- * Set a user readable error message. This should be set when the state is
- * {@link PlaybackState#STATE_ERROR}.
- */
- public void setErrorMessage(CharSequence errorMessage) {
- mErrorMessage = errorMessage;
- }
-
/**
* Get the {@link PlaybackState} state for the given
* {@link RemoteControlClient} state.
@@ -574,4 +490,175 @@ public final class PlaybackState implements Parcelable {
return new PlaybackState[size];
}
};
+
+ /**
+ * Builder for {@link PlaybackState} objects.
+ */
+ public static final class Builder {
+ private int mState;
+ private long mPosition;
+ private long mBufferPosition;
+ private float mSpeed;
+ private long mActions;
+ private CharSequence mErrorMessage;
+ private long mUpdateTime;
+
+ /**
+ * Creates an initially empty state builder.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Creates a builder with the same initial values as those in the from
+ * state.
+ *
+ * @param from The state to use for initializing the builder.
+ */
+ public Builder(PlaybackState from) {
+ if (from == null) {
+ return;
+ }
+ mState = from.mState;
+ mPosition = from.mPosition;
+ mBufferPosition = from.mBufferPosition;
+ mSpeed = from.mSpeed;
+ mActions = from.mActions;
+ mErrorMessage = from.mErrorMessage;
+ mUpdateTime = from.mUpdateTime;
+ }
+
+ /**
+ * Set the current state of playback.
+ *
+ *
+ *
+ * @param state The current state of playback.
+ * @param position The position in the current track in ms.
+ * @param playbackSpeed The current speed of playback as a multiple of
+ * normal playback.
+ * @param updateTime The time in the {@link SystemClock#elapsedRealtime}
+ * timebase that the position was updated at.
+ * @return this
+ */
+ public Builder setState(int state, long position, float playbackSpeed, long updateTime) {
+ mState = state;
+ mPosition = position;
+ mUpdateTime = updateTime;
+ mSpeed = playbackSpeed;
+ return this;
+ }
+
+ /**
+ * Set the current state of playback.
+ *
+ *
+ *
+ * @param state The current state of playback.
+ * @param position The position in the current track in ms.
+ * @param playbackSpeed The current speed of playback as a multiple of
+ * normal playback.
+ * @return this
+ */
+ public Builder setState(int state, long position, float playbackSpeed) {
+ return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime());
+ }
+
+ /**
+ * Set the current actions available on this session. This should use a
+ * bitmask of possible actions.
+ *
+ *
+ *
+ * @param actions The set of actions allowed.
+ * @return this
+ */
+ public Builder setActions(long actions) {
+ mActions = actions;
+ return this;
+ }
+
+ /**
+ * Set the current buffer position in ms. This is the farthest playback
+ * point that can be reached from the current position using only
+ * buffered content.
+ *
+ * @param bufferPosition The position in ms that playback is buffered
+ * to.
+ * @return this
+ */
+ public Builder setBufferPosition(long bufferPosition) {
+ mBufferPosition = bufferPosition;
+ return this;
+ }
+
+ /**
+ * Set a user readable error message. This should be set when the state
+ * is {@link PlaybackState#STATE_ERROR}.
+ *
+ * @param error The error message for display to the user.
+ * @return this
+ */
+ public Builder setErrorMessage(CharSequence error) {
+ mErrorMessage = error;
+ return this;
+ }
+
+ /**
+ * Build and return the PlaybackState instance with these values.
+ *
+ * @return A new state instance.
+ */
+ public PlaybackState build() {
+ return new PlaybackState(mState, mPosition, mUpdateTime, mSpeed, mBufferPosition,
+ mActions, mErrorMessage);
+ }
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index adfa1f239deca..2e7d33195b3ab 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -49,6 +49,9 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionLegacyHelper;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -224,6 +227,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private boolean mClosingActionMenu;
private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
+ private MediaController mMediaController;
private AudioManager mAudioManager;
private KeyguardManager mKeyguardManager;
@@ -1688,15 +1692,42 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_VOLUME_DOWN: {
+ int direction = keyCode == KeyEvent.KEYCODE_VOLUME_UP ? AudioManager.ADJUST_RAISE
+ : AudioManager.ADJUST_LOWER;
+ // If we have a session send it the volume command, otherwise
+ // use the suggested stream.
+ if (mMediaController != null) {
+ mMediaController.adjustVolumeBy(direction, AudioManager.FLAG_SHOW_UI);
+ } else {
+ MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
+ mVolumeControlStreamType, direction, AudioManager.FLAG_SHOW_UI);
+ }
+ return true;
+ }
case KeyEvent.KEYCODE_VOLUME_MUTE: {
- // Similar code is in PhoneFallbackEventHandler in case the window
- // doesn't have one of these. In this case, we execute it here and
- // eat the event instead, because we have mVolumeControlStreamType
- // and they don't.
getAudioManager().handleKeyDown(event, mVolumeControlStreamType);
return true;
}
+ // These are all the recognized media key codes in
+ // KeyEvent.isMediaKey()
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ case KeyEvent.KEYCODE_MUTE:
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
+ case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
+ if (mMediaController != null) {
+ if (mMediaController.dispatchMediaButtonEvent(event)) {
+ return true;
+ }
+ }
+ }
case KeyEvent.KEYCODE_MENU: {
onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event);
@@ -1750,7 +1781,19 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_VOLUME_DOWN: {
+ // If we have a session send it the volume command, otherwise
+ // use the suggested stream.
+ if (mMediaController != null) {
+ mMediaController.adjustVolumeBy(0, AudioManager.FLAG_PLAY_SOUND
+ | AudioManager.FLAG_VIBRATE);
+ } else {
+ MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
+ mVolumeControlStreamType, 0,
+ AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE);
+ }
+ return true;
+ }
case KeyEvent.KEYCODE_VOLUME_MUTE: {
// Similar code is in PhoneFallbackEventHandler in case the window
// doesn't have one of these. In this case, we execute it here and
@@ -1759,6 +1802,25 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
getAudioManager().handleKeyUp(event, mVolumeControlStreamType);
return true;
}
+ // These are all the recognized media key codes in
+ // KeyEvent.isMediaKey()
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ case KeyEvent.KEYCODE_MUTE:
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
+ case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
+ if (mMediaController != null) {
+ if (mMediaController.dispatchMediaButtonEvent(event)) {
+ return true;
+ }
+ }
+ }
case KeyEvent.KEYCODE_MENU: {
onKeyUpPanel(featureId < 0 ? FEATURE_OPTIONS_PANEL : featureId,
@@ -3773,6 +3835,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
return mVolumeControlStreamType;
}
+ @Override
+ public void setMediaController(MediaController controller) {
+ mMediaController = controller;
+ }
+
+ @Override
+ public MediaController getMediaController() {
+ return mMediaController;
+ }
+
private boolean isTranslucent() {
TypedArray a = getWindowStyle();
return a.getBoolean(a.getResourceId(
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 341c7a90d556d..01a21f406559a 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -505,16 +505,19 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
|| state.getState() == PlaybackState.STATE_FAST_FORWARDING
|| state.getState() == PlaybackState.STATE_REWINDING) {
long updateTime = state.getLastPositionUpdateTime();
+ long currentTime = SystemClock.elapsedRealtime();
if (updateTime > 0) {
- long position = (long) (state.getPlaybackRate()
- * (SystemClock.elapsedRealtime() - updateTime)) + state.getPosition();
+ long position = (long) (state.getPlaybackSpeed()
+ * (currentTime - updateTime)) + state.getPosition();
if (duration >= 0 && position > duration) {
position = duration;
} else if (position < 0) {
position = 0;
}
- result = new PlaybackState(state);
- result.setState(state.getState(), position, state.getPlaybackRate());
+ PlaybackState.Builder builder = new PlaybackState.Builder(state);
+ builder.setState(state.getState(), position, state.getPlaybackSpeed(),
+ currentTime);
+ result = builder.build();
}
}
}
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerController.java b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
index 802f473e69d39..9cbb455bc6eb2 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerController.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
@@ -18,12 +18,14 @@ package com.android.onemedia;
import android.media.MediaMetadata;
import android.media.session.MediaController;
+import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -43,7 +45,7 @@ public class PlayerController {
protected MediaController.TransportControls mTransportControls;
private final Intent mServiceIntent;
- private Context mContext;
+ private Activity mContext;
private Listener mListener;
private SessionCallback mControllerCb;
private MediaSessionManager mManager;
@@ -51,7 +53,7 @@ public class PlayerController {
private boolean mResumed;
- public PlayerController(Context context, Intent serviceIntent) {
+ public PlayerController(Activity context, Intent serviceIntent) {
mContext = context;
if (serviceIntent == null) {
mServiceIntent = new Intent(mContext, PlayerService.class);
@@ -140,6 +142,7 @@ public class PlayerController {
mBinder = null;
mController = null;
mTransportControls = null;
+ mContext.setMediaController(null);
Log.d(TAG, "Disconnected from PlayerService");
if (mListener != null) {
@@ -151,12 +154,15 @@ public class PlayerController {
public void onServiceConnected(ComponentName name, IBinder service) {
mBinder = IPlayerService.Stub.asInterface(service);
Log.d(TAG, "service is " + service + " binder is " + mBinder);
+ MediaSession.Token token;
try {
- mController = MediaController.fromToken(mBinder.getSessionToken());
+ token = mBinder.getSessionToken();
} catch (RemoteException e) {
Log.e(TAG, "Error getting session", e);
return;
}
+ mController = MediaController.fromToken(token);
+ mContext.setMediaController(mController);
mController.addCallback(mControllerCb, mHandler);
mTransportControls = mController.getTransportControls();
Log.d(TAG, "Ready to use PlayerService");
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
index 7c0eabeb840ac..78353b20fde14 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
@@ -28,6 +28,7 @@ import android.media.session.PlaybackState;
import android.os.Bundle;
import android.support.media.protocols.MediaPlayerProtocol;
import android.support.media.protocols.MediaPlayerProtocol.MediaStatus;
+import android.os.SystemClock;
import android.util.Log;
import android.view.KeyEvent;
@@ -59,9 +60,9 @@ public class PlayerSession {
mRenderer = new LocalRenderer(context, null);
mCallback = new SessionCb();
mRenderListener = new RenderListener();
- mPlaybackState = new PlaybackState();
- mPlaybackState.setActions(PlaybackState.ACTION_PAUSE
- | PlaybackState.ACTION_PLAY);
+ PlaybackState.Builder psBob = new PlaybackState.Builder();
+ psBob.setActions(PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY);
+ mPlaybackState = psBob.build();
mRenderer.registerListener(mRenderListener);
}
@@ -131,7 +132,10 @@ public class PlayerSession {
private void updateState(int newState) {
float rate = newState == PlaybackState.STATE_PLAYING ? 1 : 0;
long position = mRenderer == null ? -1 : mRenderer.getSeekPosition();
- mPlaybackState.setState(newState, position, rate);
+ PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
+ bob.setState(newState, position, rate, SystemClock.elapsedRealtime());
+ bob.setErrorMessage(null);
+ mPlaybackState = bob.build();
mSession.setPlaybackState(mPlaybackState);
}
@@ -144,10 +148,12 @@ public class PlayerSession {
@Override
public void onError(int type, int extra, Bundle extras, Throwable error) {
Log.d(TAG, "Sending onError with type " + type + " and extra " + extra);
- mPlaybackState.setState(PlaybackState.STATE_ERROR, -1, 0);
+ PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
+ bob.setState(PlaybackState.STATE_ERROR, -1, 0, 0);
if (error != null) {
- mPlaybackState.setErrorMessage(error.getLocalizedMessage());
+ bob.setErrorMessage(error.getLocalizedMessage());
}
+ mPlaybackState = bob.build();
mSession.setPlaybackState(mPlaybackState);
if (mListener != null) {
mListener.onPlayStateChanged(mPlaybackState);
@@ -156,36 +162,41 @@ public class PlayerSession {
@Override
public void onStateChanged(int newState) {
- if (newState != Renderer.STATE_ERROR) {
- mPlaybackState.setErrorMessage(null);
- }
long position = -1;
if (mRenderer != null) {
position = mRenderer.getSeekPosition();
}
+ int pbState;
+ float rate = 0;
+ String errorMsg = null;
switch (newState) {
case Renderer.STATE_ENDED:
case Renderer.STATE_STOPPED:
- mPlaybackState.setState(PlaybackState.STATE_STOPPED, position, 0);
+ pbState = PlaybackState.STATE_STOPPED;
break;
case Renderer.STATE_INIT:
case Renderer.STATE_PREPARING:
- mPlaybackState.setState(PlaybackState.STATE_BUFFERING, position, 0);
+ pbState = PlaybackState.STATE_BUFFERING;
break;
case Renderer.STATE_ERROR:
- mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0);
+ pbState = PlaybackState.STATE_ERROR;
break;
case Renderer.STATE_PAUSED:
- mPlaybackState.setState(PlaybackState.STATE_PAUSED, position, 0);
+ pbState = PlaybackState.STATE_PAUSED;
break;
case Renderer.STATE_PLAYING:
- mPlaybackState.setState(PlaybackState.STATE_PLAYING, position, 1);
+ pbState = PlaybackState.STATE_PLAYING;
+ rate = 1;
break;
default:
- mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0);
- mPlaybackState.setErrorMessage("unkown state");
+ pbState = PlaybackState.STATE_ERROR;
+ errorMsg = "unknown state";
break;
}
+ PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
+ bob.setState(pbState, position, rate, SystemClock.elapsedRealtime());
+ bob.setErrorMessage(errorMsg);
+ mPlaybackState = bob.build();
mSession.setPlaybackState(mPlaybackState);
if (mListener != null) {
mListener.onPlayStateChanged(mPlaybackState);
@@ -200,7 +211,10 @@ public class PlayerSession {
public void onFocusLost() {
Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED);
long position = mRenderer == null ? -1 : mRenderer.getSeekPosition();
- mPlaybackState.setState(PlaybackState.STATE_PAUSED, position, 0);
+ PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
+ bob.setState(PlaybackState.STATE_PAUSED, position, 0, SystemClock.elapsedRealtime());
+ bob.setErrorMessage(null);
+ mPlaybackState = bob.build();
mSession.setPlaybackState(mPlaybackState);
if (mListener != null) {
mListener.onPlayStateChanged(mPlaybackState);
diff --git a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
index 2e1478bc3f54c..5845e48db6e5b 100644
--- a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
+++ b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
@@ -29,6 +29,9 @@ import android.os.Process;
import android.support.media.protocols.MediaPlayerProtocol;
import android.support.media.protocols.MediaPlayerProtocol.MediaInfo;
import android.support.media.protocols.MediaPlayerProtocol.MediaStatus;
+import android.os.Looper;
+import android.os.ResultReceiver;
+import android.os.SystemClock;
import android.util.Log;
import com.android.onemedia.playback.LocalRenderer;
@@ -60,9 +63,9 @@ public class OneMediaRouteProvider extends MediaRouteService {
mHandler = new Handler();
mRenderer = new LocalRenderer(this, null);
mRenderListener = new RenderListener();
- mPlaybackState = new PlaybackState();
- mPlaybackState.setActions(PlaybackState.ACTION_PAUSE
- | PlaybackState.ACTION_PLAY);
+ PlaybackState.Builder bob = new PlaybackState.Builder();
+ bob.setActions(PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY);
+ mPlaybackState = bob.build();
mRenderer.registerListener(mRenderListener);
}
@@ -178,36 +181,41 @@ public class OneMediaRouteProvider extends MediaRouteService {
@Override
public void onStateChanged(int newState) {
- if (newState != Renderer.STATE_ERROR) {
- mPlaybackState.setErrorMessage(null);
- }
long position = -1;
if (mRenderer != null) {
position = mRenderer.getSeekPosition();
}
+ int pbState;
+ float rate = 0;
+ String errorMsg = null;
switch (newState) {
case Renderer.STATE_ENDED:
case Renderer.STATE_STOPPED:
- mPlaybackState.setState(PlaybackState.STATE_STOPPED, position, 0);
+ pbState = PlaybackState.STATE_STOPPED;
break;
case Renderer.STATE_INIT:
case Renderer.STATE_PREPARING:
- mPlaybackState.setState(PlaybackState.STATE_BUFFERING, position, 0);
+ pbState = PlaybackState.STATE_BUFFERING;
break;
case Renderer.STATE_ERROR:
- mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0);
+ pbState = PlaybackState.STATE_ERROR;
break;
case Renderer.STATE_PAUSED:
- mPlaybackState.setState(PlaybackState.STATE_PAUSED, position, 0);
+ pbState = PlaybackState.STATE_PAUSED;
break;
case Renderer.STATE_PLAYING:
- mPlaybackState.setState(PlaybackState.STATE_PLAYING, position, 1);
+ pbState = PlaybackState.STATE_PLAYING;
+ rate = 1;
break;
default:
- mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0);
- mPlaybackState.setErrorMessage("unkown state");
+ pbState = PlaybackState.STATE_ERROR;
+ errorMsg = "unknown state";
break;
}
+ PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
+ bob.setState(pbState, position, rate, SystemClock.elapsedRealtime());
+ bob.setErrorMessage(errorMsg);
+ mPlaybackState = bob.build();
sendStatusUpdate(mPlaybackState.getState());
}
@@ -218,8 +226,9 @@ public class OneMediaRouteProvider extends MediaRouteService {
@Override
public void onFocusLost() {
- Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED);
- mPlaybackState.setState(PlaybackState.STATE_PAUSED, mRenderer.getSeekPosition(), 0);
+ Log.d(TAG, "Focus lost, pausing");
+ // Don't update state here, we'll get a separate call to
+ // onStateChanged when it pauses
mRenderer.onPause();
}