Merge "Fixes preference-ktx test flakes / failures" into androidx-master-dev
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
index 79ee123..03661d9 100644
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -1,5 +1,6 @@
 <component name="ProjectCodeStyleConfiguration">
   <state>
     <option name="USE_PER_PROJECT_SETTINGS" value="true" />
+    <option name="PREFERRED_PROJECT_CODE_STYLE" value="AndroidStyle" />
   </state>
 </component>
\ No newline at end of file
diff --git a/appcompat/resources/src/androidTest/java/androidx/appcompat/graphics/drawable/AnimatedStateListDrawableCompatTest.java b/appcompat/resources/src/androidTest/java/androidx/appcompat/graphics/drawable/AnimatedStateListDrawableCompatTest.java
index 1cfe0e6..10c86dc 100644
--- a/appcompat/resources/src/androidTest/java/androidx/appcompat/graphics/drawable/AnimatedStateListDrawableCompatTest.java
+++ b/appcompat/resources/src/androidTest/java/androidx/appcompat/graphics/drawable/AnimatedStateListDrawableCompatTest.java
@@ -22,7 +22,6 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
 
 import android.content.Context;
 import android.graphics.Canvas;
@@ -40,7 +39,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mockito;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
@@ -79,11 +77,11 @@
             // Expected.
         }
 
-        Drawable unfocused = mock(Drawable.class);
+        Drawable unfocused = new MockDrawable();
         asld.addState(StateSet.WILD_CARD, unfocused, R.id.focused);
         assertEquals(1, asld.getStateCount());
 
-        Drawable focused = mock(Drawable.class);
+        Drawable focused = new MockDrawable();
         asld.addState(STATE_FOCUSED, focused, R.id.unfocused);
         assertEquals(2, asld.getStateCount());
     }
@@ -92,8 +90,8 @@
     public void testAddTransition() {
         AnimatedStateListDrawableCompat asld = new AnimatedStateListDrawableCompat();
 
-        Drawable focused = mock(Drawable.class);
-        Drawable unfocused = mock(Drawable.class);
+        Drawable focused = new MockDrawable();
+        Drawable unfocused = new MockDrawable();
         asld.addState(STATE_FOCUSED, focused, R.id.focused);
         asld.addState(StateSet.WILD_CARD, unfocused, R.id.unfocused);
 
@@ -126,8 +124,8 @@
     public void testOnStateChange() {
         AnimatedStateListDrawableCompat asld = new AnimatedStateListDrawableCompat();
 
-        Drawable focused = mock(Drawable.class);
-        Drawable unfocused = mock(Drawable.class);
+        Drawable focused = new MockDrawable();
+        Drawable unfocused = new MockDrawable();
         asld.addState(STATE_FOCUSED, focused, R.id.focused);
         asld.addState(StateSet.WILD_CARD, unfocused, R.id.unfocused);
 
@@ -189,8 +187,8 @@
         assertNotNull(asld.getConstantState());
 
         // When a drawable who returns a null constant state is added
-        Drawable noConstantStateDrawable = mock(Drawable.class);
-        Mockito.when(noConstantStateDrawable.getConstantState()).thenReturn(null);
+        // MockDrawable returns null from getConstantState() - same as Drawable's default impl
+        Drawable noConstantStateDrawable = new MockDrawable();
         asld.addState(StateSet.WILD_CARD, noConstantStateDrawable, R.id.focused);
 
         // Then the ASLD should also return a null constant state
diff --git a/browser/OWNERS b/browser/OWNERS
index a0bf18a..b6d0e07 100644
--- a/browser/OWNERS
+++ b/browser/OWNERS
@@ -1,2 +1,2 @@
 lizeb@google.com
-yusufo@google.com
\ No newline at end of file
+peconn@google.com
diff --git a/browser/api/1.0.0.txt b/browser/api/1.1.0-alpha01.txt
similarity index 97%
rename from browser/api/1.0.0.txt
rename to browser/api/1.1.0-alpha01.txt
index a1ecbdd..6d5793a 100644
--- a/browser/api/1.0.0.txt
+++ b/browser/api/1.1.0-alpha01.txt
@@ -4,14 +4,15 @@
   public class BrowserActionItem {
     ctor public BrowserActionItem(String, android.app.PendingIntent, @DrawableRes int);
     ctor public BrowserActionItem(String, android.app.PendingIntent);
-    method public android.app.PendingIntent! getAction();
+    method public android.app.PendingIntent getAction();
     method public int getIconId();
-    method public String! getTitle();
+    method public String getTitle();
   }
 
   public class BrowserActionsIntent {
-    method public static String! getCreatorPackageName(android.content.Intent!);
+    method @Deprecated public static String? getCreatorPackageName(android.content.Intent);
     method public android.content.Intent getIntent();
+    method public static String? getUntrustedCreatorPackageName(android.content.Intent);
     method public static void launchIntent(android.content.Context!, android.content.Intent!);
     method public static void openBrowserAction(android.content.Context!, android.net.Uri!);
     method public static void openBrowserAction(android.content.Context!, android.net.Uri!, int, java.util.ArrayList<androidx.browser.browseractions.BrowserActionItem>!, android.app.PendingIntent!);
@@ -72,7 +73,7 @@
     method public static boolean connectAndInitialize(android.content.Context!, String!);
     method public android.os.Bundle! extraCommand(String!, android.os.Bundle!);
     method public static String! getPackageName(android.content.Context!, java.util.List<java.lang.String>?);
-    method public static String! getPackageName(android.content.Context!, java.util.List<java.lang.String>?, boolean);
+    method public static String? getPackageName(android.content.Context, java.util.List<java.lang.String>?, boolean);
     method public androidx.browser.customtabs.CustomTabsSession! newSession(androidx.browser.customtabs.CustomTabsCallback!);
     method public boolean warmup(long);
   }
diff --git a/browser/api/current.txt b/browser/api/current.txt
index a1ecbdd..6d5793a 100644
--- a/browser/api/current.txt
+++ b/browser/api/current.txt
@@ -4,14 +4,15 @@
   public class BrowserActionItem {
     ctor public BrowserActionItem(String, android.app.PendingIntent, @DrawableRes int);
     ctor public BrowserActionItem(String, android.app.PendingIntent);
-    method public android.app.PendingIntent! getAction();
+    method public android.app.PendingIntent getAction();
     method public int getIconId();
-    method public String! getTitle();
+    method public String getTitle();
   }
 
   public class BrowserActionsIntent {
-    method public static String! getCreatorPackageName(android.content.Intent!);
+    method @Deprecated public static String? getCreatorPackageName(android.content.Intent);
     method public android.content.Intent getIntent();
+    method public static String? getUntrustedCreatorPackageName(android.content.Intent);
     method public static void launchIntent(android.content.Context!, android.content.Intent!);
     method public static void openBrowserAction(android.content.Context!, android.net.Uri!);
     method public static void openBrowserAction(android.content.Context!, android.net.Uri!, int, java.util.ArrayList<androidx.browser.browseractions.BrowserActionItem>!, android.app.PendingIntent!);
@@ -72,7 +73,7 @@
     method public static boolean connectAndInitialize(android.content.Context!, String!);
     method public android.os.Bundle! extraCommand(String!, android.os.Bundle!);
     method public static String! getPackageName(android.content.Context!, java.util.List<java.lang.String>?);
-    method public static String! getPackageName(android.content.Context!, java.util.List<java.lang.String>?, boolean);
+    method public static String? getPackageName(android.content.Context, java.util.List<java.lang.String>?, boolean);
     method public androidx.browser.customtabs.CustomTabsSession! newSession(androidx.browser.customtabs.CustomTabsCallback!);
     method public boolean warmup(long);
   }
diff --git a/browser/api/res-1.1.0-alpha01.txt b/browser/api/res-1.1.0-alpha01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/browser/api/res-1.1.0-alpha01.txt
diff --git a/browser/build.gradle b/browser/build.gradle
index c8a3fca..feed454 100644
--- a/browser/build.gradle
+++ b/browser/build.gradle
@@ -8,7 +8,7 @@
 
 android {
     defaultConfig {
-        minSdkVersion 15
+        minSdkVersion 16
     }
 }
 
@@ -19,6 +19,8 @@
     api(project(":collection"))
     api(project(":legacy-support-core-ui"))
 
+    implementation(project(":concurrent:concurrent-futures"))
+
     androidTestImplementation(TEST_EXT_JUNIT)
     androidTestImplementation(TEST_CORE)
     androidTestImplementation(TEST_RUNNER)
diff --git a/browser/src/androidTest/java/androidx/browser/browseractions/BrowserActionsFallbackMenuUiTest.java b/browser/src/androidTest/java/androidx/browser/browseractions/BrowserActionsFallbackMenuUiTest.java
index 0d5ed92..1ed34b8 100644
--- a/browser/src/androidTest/java/androidx/browser/browseractions/BrowserActionsFallbackMenuUiTest.java
+++ b/browser/src/androidTest/java/androidx/browser/browseractions/BrowserActionsFallbackMenuUiTest.java
@@ -31,6 +31,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.LargeTest;
 import androidx.test.rule.ActivityTestRule;
+import androidx.testutils.PollingCheck;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -54,11 +55,18 @@
             new ActivityTestRule<>(TestActivity.class);
     private Context mContext;
     private List<BrowserActionItem> mMenuItems;
+    private List<String> mMenuItemTitles;
 
     @Before
     public void setup() {
         mContext = mActivityTestRule.getActivity();
         mMenuItems = createMenuItems();
+        mMenuItemTitles = new ArrayList<>();
+        mMenuItemTitles.add(mContext.getString(R.string.fallback_menu_item_open_in_browser));
+        mMenuItemTitles.add(mContext.getString(R.string.fallback_menu_item_copy_link));
+        mMenuItemTitles.add(mContext.getString(R.string.fallback_menu_item_share_link));
+        mMenuItemTitles.add(CUSTOM_ITEM_TITLE_1);
+        mMenuItemTitles.add(CUSTOM_ITEM_TITLE_2);
     }
 
     private List<BrowserActionItem> createMenuItems() {
@@ -130,15 +138,19 @@
                 (TextView) contentView.findViewById(R.id.browser_actions_header_text);
         assertNotNull(urlTextView);
         assertEquals(TEST_URL, urlTextView.getText());
-        ListView menuListView =
+        final ListView menuListView =
                 (ListView) contentView.findViewById(R.id.browser_actions_menu_items);
         assertNotNull(menuListView);
-        assertEquals(2, menuListView.getCount());
-        TextView menuItemTitleView1 = (TextView) menuListView.getChildAt(0).findViewById(
-                R.id.browser_actions_menu_item_text);
-        assertEquals(CUSTOM_ITEM_TITLE_1, menuItemTitleView1.getText());
-        TextView menuItemTitleView2 = (TextView) menuListView.getChildAt(1).findViewById(
-                R.id.browser_actions_menu_item_text);
-        assertEquals(CUSTOM_ITEM_TITLE_2, menuItemTitleView2.getText());
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mMenuItemTitles.size() == menuListView.getCount();
+            }
+        });
+        for (int i = 0; i < mMenuItemTitles.size(); i++) {
+            TextView menuItemTitleView = (TextView) menuListView.getChildAt(i).findViewById(
+                    R.id.browser_actions_menu_item_text);
+            assertEquals(mMenuItemTitles.get(i), menuItemTitleView.getText());
+        }
     }
-}
+}
\ No newline at end of file
diff --git a/browser/src/androidTest/java/androidx/browser/browseractions/BrowserActionsIntentTest.java b/browser/src/androidTest/java/androidx/browser/browseractions/BrowserActionsIntentTest.java
index 69bed08..9311270 100644
--- a/browser/src/androidTest/java/androidx/browser/browseractions/BrowserActionsIntentTest.java
+++ b/browser/src/androidTest/java/androidx/browser/browseractions/BrowserActionsIntentTest.java
@@ -62,7 +62,8 @@
         assertEquals(BrowserActionsIntent.URL_TYPE_NONE,
                 intent.getIntExtra(BrowserActionsIntent.EXTRA_TYPE, 0));
         assertTrue(intent.hasExtra(BrowserActionsIntent.EXTRA_APP_ID));
-        assertEquals(mContext.getPackageName(), BrowserActionsIntent.getCreatorPackageName(intent));
+        assertEquals(mContext.getPackageName(),
+                BrowserActionsIntent.getUntrustedCreatorPackageName(intent));
         assertFalse(intent.hasExtra(BrowserActionsIntent.EXTRA_SELECTED_ACTION_PENDING_INTENT));
     }
 
diff --git a/browser/src/androidTest/java/androidx/browser/customtabs/PostMessageTest.java b/browser/src/androidTest/java/androidx/browser/customtabs/PostMessageTest.java
index 66b7230..3adef06 100644
--- a/browser/src/androidTest/java/androidx/browser/customtabs/PostMessageTest.java
+++ b/browser/src/androidTest/java/androidx/browser/customtabs/PostMessageTest.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Bundle;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -37,9 +38,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-
 /**
  * Tests for a complete loop between a browser side {@link CustomTabsService}
  * and a client side {@link PostMessageService}. Both services are bound to through
@@ -50,6 +51,8 @@
 @LargeTest
 public class PostMessageTest {
     @Rule
+    public final ServiceTestRule mServiceRule;
+    @Rule
     public final ActivityTestRule<TestActivity> mActivityTestRule;
     private TestCustomTabsCallback mCallback;
     private Context mContext;
@@ -61,6 +64,7 @@
 
     public PostMessageTest() {
         mActivityTestRule = new ActivityTestRule<TestActivity>(TestActivity.class);
+        mServiceRule = new ServiceTestRule();
         mCustomTabsServiceConnected = new AtomicBoolean(false);
     }
 
@@ -73,15 +77,21 @@
             @Override
             public void extraCallback(String callbackName, Bundle args) {
                 if (TestCustomTabsService.CALLBACK_BIND_TO_POST_MESSAGE.equals(callbackName)) {
-                    Intent postMessageServiceIntent = new Intent();
-                    postMessageServiceIntent.setClassName(
-                            mContext.getPackageName(), PostMessageService.class.getName());
-                    try {
-                        mContext.bindService(postMessageServiceIntent,
-                                mPostMessageServiceConnection, Context.BIND_AUTO_CREATE);
-                    } catch (Exception e) {
-                        fail();
-                    }
+                    // This gets run on the UI thread, where mServiceRule.bindService will not work.
+                    AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
+                        @Override
+                        public void run() {
+                            try {
+                                Intent postMessageServiceIntent = new Intent();
+                                postMessageServiceIntent.setClassName(mContext.getPackageName(),
+                                        PostMessageService.class.getName());
+                                mServiceRule.bindService(postMessageServiceIntent,
+                                        mPostMessageServiceConnection, Context.BIND_AUTO_CREATE);
+                            } catch (TimeoutException e) {
+                                fail();
+                            }
+                        }
+                    });
                 }
             }
         };
@@ -89,8 +99,8 @@
         mCustomTabsServiceConnection = new CustomTabsServiceConnection() {
             @Override
             public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) {
-                mSession = client.newSession(mCallback);
                 mCustomTabsServiceConnected.set(true);
+                mSession = client.newSession(mCallback);
             }
 
             @Override
@@ -114,9 +124,9 @@
         customTabsServiceIntent.setClassName(
                 mContext.getPackageName(), TestCustomTabsService.class.getName());
         try {
-            mContext.bindService(customTabsServiceIntent,
+            mServiceRule.bindService(customTabsServiceIntent,
                     mCustomTabsServiceConnection, Context.BIND_AUTO_CREATE);
-        } catch (Exception e) {
+        } catch (TimeoutException e) {
             fail();
         }
     }
diff --git a/browser/src/androidTest/java/androidx/browser/customtabs/TestCustomTabsCallback.java b/browser/src/androidTest/java/androidx/browser/customtabs/TestCustomTabsCallback.java
index 7c48245..6353398 100644
--- a/browser/src/androidTest/java/androidx/browser/customtabs/TestCustomTabsCallback.java
+++ b/browser/src/androidTest/java/androidx/browser/customtabs/TestCustomTabsCallback.java
@@ -55,7 +55,7 @@
 
         @Override
         public void onRelationshipValidationResult(int relation, Uri origin, boolean result,
-                                                   Bundle extras) throws RemoteException {
+                Bundle extras) throws RemoteException {
             TestCustomTabsCallback.this.onRelationshipValidationResult(
                     relation, origin, result, extras);
         }
diff --git a/browser/src/androidTest/java/androidx/browser/customtabs/TestCustomTabsService.java b/browser/src/androidTest/java/androidx/browser/customtabs/TestCustomTabsService.java
index c3057b2f..071d1c2 100644
--- a/browser/src/androidTest/java/androidx/browser/customtabs/TestCustomTabsService.java
+++ b/browser/src/androidTest/java/androidx/browser/customtabs/TestCustomTabsService.java
@@ -43,7 +43,7 @@
 
     @Override
     protected boolean mayLaunchUrl(CustomTabsSessionToken sessionToken,
-                                   Uri url, Bundle extras, List<Bundle> otherLikelyBundles) {
+            Uri url, Bundle extras, List<Bundle> otherLikelyBundles) {
         return false;
     }
 
@@ -74,7 +74,7 @@
 
     @Override
     protected boolean validateRelationship(CustomTabsSessionToken sessionToken,
-                                           @Relation int relation, Uri origin, Bundle extras) {
+            @Relation int relation, Uri origin, Bundle extras) {
         return false;
     }
 }
diff --git a/browser/src/main/aidl/android/support/customtabs/ICustomTabsCallback.aidl b/browser/src/main/aidl/android/support/customtabs/ICustomTabsCallback.aidl
index 3e2c48c..a5dd8ea 100644
--- a/browser/src/main/aidl/android/support/customtabs/ICustomTabsCallback.aidl
+++ b/browser/src/main/aidl/android/support/customtabs/ICustomTabsCallback.aidl
@@ -28,4 +28,4 @@
     void onMessageChannelReady(in Bundle extras) = 3;
     void onPostMessage(String message, in Bundle extras) = 4;
     void onRelationshipValidationResult(int relation, in Uri origin, boolean result, in Bundle extras) = 5;
-}
+}
\ No newline at end of file
diff --git a/browser/src/main/aidl/android/support/customtabs/ICustomTabsService.aidl b/browser/src/main/aidl/android/support/customtabs/ICustomTabsService.aidl
index 376c2a4..c89d9db 100644
--- a/browser/src/main/aidl/android/support/customtabs/ICustomTabsService.aidl
+++ b/browser/src/main/aidl/android/support/customtabs/ICustomTabsService.aidl
@@ -37,4 +37,4 @@
     boolean requestPostMessageChannel(in ICustomTabsCallback callback, in Uri postMessageOrigin) = 6;
     int postMessage(in ICustomTabsCallback callback, String message, in Bundle extras) = 7;
     boolean validateRelationship(in ICustomTabsCallback callback, int relation, in Uri origin, in Bundle extras) = 8;
-}
+}
\ No newline at end of file
diff --git a/browser/src/main/aidl/android/support/customtabs/IPostMessageService.aidl b/browser/src/main/aidl/android/support/customtabs/IPostMessageService.aidl
index 2c8a605..666fe83c 100644
--- a/browser/src/main/aidl/android/support/customtabs/IPostMessageService.aidl
+++ b/browser/src/main/aidl/android/support/customtabs/IPostMessageService.aidl
@@ -27,4 +27,4 @@
 interface IPostMessageService {
     void onMessageChannelReady(in ICustomTabsCallback callback, in Bundle extras) = 1;
     void onPostMessage(in ICustomTabsCallback callback, String message, in Bundle extras) = 2;
-}
+}
\ No newline at end of file
diff --git a/browser/src/main/java/androidx/browser/browseractions/BrowserActionItem.java b/browser/src/main/java/androidx/browser/browseractions/BrowserActionItem.java
index 4b657c4..e912d12 100644
--- a/browser/src/main/java/androidx/browser/browseractions/BrowserActionItem.java
+++ b/browser/src/main/java/androidx/browser/browseractions/BrowserActionItem.java
@@ -16,10 +16,16 @@
 
 package androidx.browser.browseractions;
 
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
 import android.app.PendingIntent;
+import android.net.Uri;
 
 import androidx.annotation.DrawableRes;
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
 
 /**
  * A wrapper class holding custom item of Browser Actions menu.
@@ -29,7 +35,9 @@
     private final String mTitle;
     private final PendingIntent mAction;
     @DrawableRes
-    private final int mIconId;
+    private int mIconId;
+    private Uri mIconUri;
+    private Runnable mRunnableAction;
 
     /**
      * Constructor for BrowserActionItem with icon, string and action provided.
@@ -45,6 +53,35 @@
     }
 
     /**
+     * Constructor for BrowserActionItem with icon access through a uri.
+     * @param title The string shown for a custom item.
+     * @param action The PendingIntent executed when a custom item is selected
+     * @param iconUri The {@link Uri} used to access the icon file. Note: make sure this is
+     * generated from {@link BrowserServiceFileProvider.generateUri(Context, Bitmap, String,
+     * int, List<ResolveInfo>)}.
+     */
+    /** @hide */
+    @RestrictTo(LIBRARY_GROUP)
+    public BrowserActionItem(
+            @NonNull String title, @NonNull PendingIntent action, @NonNull Uri iconUri) {
+        mTitle = title;
+        mAction = action;
+        mIconUri = iconUri;
+    }
+
+    /**
+     * Constructs a predefined fallback menu item with a Runnable action. The item will have no
+     * icon and no custom PendingIntent action.
+     * @param title The title of the menu item.
+     * @param action The {@link Runnable} action to be executed when user choose the item.
+     */
+    BrowserActionItem(@NonNull String title, @NonNull Runnable action) {
+        mTitle = title;
+        mAction = null;
+        mRunnableAction = action;
+    }
+
+    /**
      * Constructor for BrowserActionItem with only string and action provided.
      * @param title The icon shown for a custom item.
      * @param action The string shown for a custom item.
@@ -63,6 +100,7 @@
     /**
      * @return The title of a custom item.
      */
+    @NonNull
     public String getTitle() {
         return mTitle;
     }
@@ -70,7 +108,28 @@
     /**
      * @return The action of a custom item.
      */
+    @NonNull
     public PendingIntent getAction() {
         return mAction;
     }
+
+    /**
+     * @return The uri used to get the icon of a custom item.
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    @Nullable
+    public Uri getIconUri() {
+        return mIconUri;
+    }
+
+    /**
+     * @return The {@link Runnable} action of a predefined fallback menu item.
+     */
+    /** @hide */
+    @RestrictTo(LIBRARY_GROUP)
+    @Nullable
+    Runnable getRunnableAction() {
+        return mRunnableAction;
+    }
 }
diff --git a/browser/src/main/java/androidx/browser/browseractions/BrowserActionsFallbackMenuAdapter.java b/browser/src/main/java/androidx/browser/browseractions/BrowserActionsFallbackMenuAdapter.java
index a82ecc2..a1756eb 100644
--- a/browser/src/main/java/androidx/browser/browseractions/BrowserActionsFallbackMenuAdapter.java
+++ b/browser/src/main/java/androidx/browser/browseractions/BrowserActionsFallbackMenuAdapter.java
@@ -17,7 +17,9 @@
 package androidx.browser.browseractions;
 
 import android.content.Context;
+import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -28,7 +30,11 @@
 import androidx.browser.R;
 import androidx.core.content.res.ResourcesCompat;
 
+import com.google.common.util.concurrent.ListenableFuture;
+
 import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
 
 /**
  * The adapter to display the icon and title of custom Browser Actions item.
@@ -60,7 +66,7 @@
     @Override
     public View getView(int position, View convertView, ViewGroup parent) {
         final BrowserActionItem menuItem = mMenuItems.get(position);
-        ViewHolderItem viewHolder;
+        final ViewHolderItem viewHolder;
         if (convertView == null) {
             convertView = LayoutInflater.from(mContext).inflate(
                     R.layout.browser_actions_context_menu_row, null);
@@ -74,13 +80,47 @@
             viewHolder = (ViewHolderItem) convertView.getTag();
         }
 
-        viewHolder.mText.setText(menuItem.getTitle());
+        final String titleText = menuItem.getTitle();
+        viewHolder.mText.setText(titleText);
         if (menuItem.getIconId() != 0) {
             Drawable drawable = ResourcesCompat.getDrawable(
                     mContext.getResources(), menuItem.getIconId(), null);
             viewHolder.mIcon.setImageDrawable(drawable);
+        } else if (menuItem.getIconUri() != null) {
+            final ListenableFuture<Bitmap> bitmapFuture = BrowserServiceFileProvider
+                    .loadBitmap(mContext.getContentResolver(), menuItem.getIconUri());
+
+            bitmapFuture.addListener(new Runnable() {
+                @Override
+                public void run() {
+                    // ViewHolder has been reused by other item.
+                    if (!TextUtils.equals(titleText, viewHolder.mText.getText())) return;
+
+                    Bitmap bitmap = null;
+                    try {
+                        bitmap = bitmapFuture.get();
+                    } catch (ExecutionException | InterruptedException e) {
+                        // Ignore and just don't use the image.
+                    }
+
+                    if (bitmap != null) {
+                        viewHolder.mIcon.setVisibility(View.VISIBLE);
+                        viewHolder.mIcon.setImageBitmap(bitmap);
+                    } else {
+                        viewHolder.mIcon.setVisibility(View.INVISIBLE);
+                        viewHolder.mIcon.setImageBitmap(null);
+                    }
+                }
+            }, new Executor() {
+                @Override
+                public void execute(Runnable runnable) {
+                    runnable.run();
+                }
+            });
+
         } else {
-            viewHolder.mIcon.setImageDrawable(null);
+            viewHolder.mIcon.setImageBitmap(null);
+            viewHolder.mIcon.setVisibility(View.INVISIBLE);
         }
         return convertView;
     }
diff --git a/browser/src/main/java/androidx/browser/browseractions/BrowserActionsFallbackMenuUi.java b/browser/src/main/java/androidx/browser/browseractions/BrowserActionsFallbackMenuUi.java
index 270efd6..ac69132 100644
--- a/browser/src/main/java/androidx/browser/browseractions/BrowserActionsFallbackMenuUi.java
+++ b/browser/src/main/java/androidx/browser/browseractions/BrowserActionsFallbackMenuUi.java
@@ -20,8 +20,11 @@
 
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
+import android.content.ClipData;
+import android.content.ClipboardManager;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.Intent;
 import android.net.Uri;
 import android.text.TextUtils;
 import android.util.Log;
@@ -30,12 +33,14 @@
 import android.widget.AdapterView;
 import android.widget.ListView;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import androidx.annotation.RestrictTo;
 import androidx.annotation.VisibleForTesting;
 import androidx.browser.R;
 import androidx.core.widget.TextViewCompat;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -51,8 +56,11 @@
 
     private static final String TAG = "BrowserActionskMenuUi";
 
-    private final Context mContext;
-    private final Uri mUri;
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    final Context mContext;
+
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    final Uri mUri;
     private final List<BrowserActionItem> mMenuItems;
 
     @SuppressWarnings("WeakerAccess") /* synthetic access */
@@ -63,13 +71,12 @@
     /**
      * @param context The {@link Context} used to show the fallback menu.
      * @param uri The uri which users click to trigger the menu.
-     * @param menuItems The custom menu items shown in the menu.
+     * @param customItems The custom menu items shown in the menu.
      */
-    BrowserActionsFallbackMenuUi(
-            Context context, Uri uri, List<BrowserActionItem> menuItems) {
+    BrowserActionsFallbackMenuUi(Context context, Uri uri, List<BrowserActionItem> customItems) {
         mContext = context;
         mUri = uri;
-        mMenuItems = menuItems;
+        mMenuItems = buildFallbackMenuItemList(context, customItems);
     }
 
     /** @hide */
@@ -79,6 +86,46 @@
         mMenuUiListener = menuUiListener;
     }
 
+    private List<BrowserActionItem> buildFallbackMenuItemList(
+            Context context, List<BrowserActionItem> customItems) {
+        List<BrowserActionItem> fallbackMenuItems = new ArrayList<>();
+        fallbackMenuItems.add(new BrowserActionItem(
+                mContext.getString(R.string.fallback_menu_item_open_in_browser),
+                buildOpenInBrowserAction()));
+        fallbackMenuItems.add(new BrowserActionItem(
+                mContext.getString(R.string.fallback_menu_item_copy_link), buildCopyAction()));
+        fallbackMenuItems.add(new BrowserActionItem(
+                mContext.getString(R.string.fallback_menu_item_share_link), buildShareAction()));
+        fallbackMenuItems.addAll(customItems);
+        return fallbackMenuItems;
+    }
+
+    private PendingIntent buildOpenInBrowserAction() {
+        Intent intent = new Intent(Intent.ACTION_VIEW, mUri);
+        return PendingIntent.getActivity(mContext, 0, intent, 0);
+    }
+
+    private PendingIntent buildShareAction() {
+        Intent intent = new Intent(Intent.ACTION_SEND);
+        intent.putExtra(Intent.EXTRA_TEXT, mUri.toString());
+        intent.setType("text/plain");
+        return PendingIntent.getActivity(mContext, 0, intent, 0);
+    }
+
+    private Runnable buildCopyAction() {
+        return new Runnable() {
+            @Override
+            public void run() {
+                ClipboardManager clipboardManager =
+                        (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
+                ClipData data = ClipData.newPlainText("url", mUri.toString());
+                clipboardManager.setPrimaryClip(data);
+                String toastMsg = mContext.getString(R.string.copy_toast_msg);
+                Toast.makeText(mContext, toastMsg, Toast.LENGTH_SHORT).show();
+            }
+        };
+    }
+
     /**
      * Shows the fallback menu.
      */
@@ -128,12 +175,16 @@
 
     @Override
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        PendingIntent action = mMenuItems.get(position).getAction();
-        try {
-            action.send();
-            mBrowserActionsDialog.dismiss();
-        } catch (CanceledException e) {
-            Log.e(TAG, "Failed to send custom item action", e);
+        BrowserActionItem menuItem = mMenuItems.get(position);
+        if (menuItem.getAction() != null) {
+            try {
+                menuItem.getAction().send();
+            } catch (CanceledException e) {
+                Log.e(TAG, "Failed to send custom item action", e);
+            }
+        } else if (menuItem.getRunnableAction() != null) {
+            menuItem.getRunnableAction().run();
         }
+        mBrowserActionsDialog.dismiss();
     }
 }
diff --git a/browser/src/main/java/androidx/browser/browseractions/BrowserActionsIntent.java b/browser/src/main/java/androidx/browser/browseractions/BrowserActionsIntent.java
index 00aaafd..8b6fd7e 100644
--- a/browser/src/main/java/androidx/browser/browseractions/BrowserActionsIntent.java
+++ b/browser/src/main/java/androidx/browser/browseractions/BrowserActionsIntent.java
@@ -16,6 +16,7 @@
 
 package androidx.browser.browseractions;
 
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
 import android.app.PendingIntent;
@@ -31,6 +32,7 @@
 import androidx.annotation.DrawableRes;
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.content.ContextCompat;
@@ -40,12 +42,13 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+
 /**
  * Class holding the {@link Intent} and start bundle for a Browser Actions Activity.
  *
  * <p>
  * <strong>Note:</strong> The constants below are public for the browser implementation's benefit.
- * You are strongly encouraged to use {@link BrowserActionsIntent.Builder}.</p>
+ * You are strongly encouraged to use {@link BrowserActionsIntent.Builder}.
  */
 public class BrowserActionsIntent {
     private static final String TAG = "BrowserActions";
@@ -55,6 +58,10 @@
     /**
      * Extra that specifies {@link PendingIntent} indicating which Application sends the {@link
      * BrowserActionsIntent}.
+     * <p>
+     * <strong>Note:</strong> The PendingIntent is self-reported and untrusted, sending application
+     * can modify it to use PendingIntent from other apps. This would return the package name from
+     * the app who creates the PendintIntent.
      */
     public static final String EXTRA_APP_ID = "androidx.browser.browseractions.APP_ID";
 
@@ -70,6 +77,12 @@
     public static final String KEY_ICON_ID = "androidx.browser.browseractions.ICON_ID";
 
     /**
+     * Extra {@link Uri} that specifies location of file for the icon of a custom item shown in the
+     * Browser Actions menu.
+     */
+    private static final String KEY_ICON_URI = "androidx.browser.browseractions.ICON_URI";
+
+    /**
      * Extra string that specifies the title of a custom item shown in the Browser Actions menu.
      */
     public static final String KEY_TITLE = "androidx.browser.browseractions.TITLE";
@@ -174,6 +187,7 @@
         private int mType;
         private ArrayList<Bundle> mMenuItems = null;
         private PendingIntent mOnItemSelectedPendingIntent = null;
+        private List<Uri> mImageUris = null;
 
         /**
          * Constructs a {@link BrowserActionsIntent.Builder} object associated with default setting
@@ -186,6 +200,7 @@
             mUri = uri;
             mType = URL_TYPE_NONE;
             mMenuItems = new ArrayList<>();
+            mImageUris = new ArrayList<>();
         }
 
         /**
@@ -215,6 +230,9 @@
                             "Custom item should contain a non-empty title and non-null intent.");
                 } else {
                     mMenuItems.add(getBundleFromItem(items.get(i)));
+                    if (items.get(i).getIconUri() != null) {
+                        mImageUris.add(items.get(i).getIconUri());
+                    }
                 }
             }
             return this;
@@ -249,6 +267,7 @@
             bundle.putString(KEY_TITLE, item.getTitle());
             bundle.putParcelable(KEY_ACTION, item.getAction());
             if (item.getIconId() != 0) bundle.putInt(KEY_ICON_ID, item.getIconId());
+            if (item.getIconUri() != null) bundle.putParcelable(KEY_ICON_URI, item.getIconUri());
             return bundle;
         }
 
@@ -266,6 +285,7 @@
                 mIntent.putExtra(
                         EXTRA_SELECTED_ACTION_PENDING_INTENT, mOnItemSelectedPendingIntent);
             }
+            BrowserServiceFileProvider.grantReadPermission(mIntent, mImageUris, mContext);
             return new BrowserActionsIntent(mIntent);
         }
     }
@@ -347,8 +367,11 @@
      * BrowserActionsIntent}.
      * @param context The context requesting for a Browser Actions menu.
      * @return List of Browser Actions providers available to handle the intent.
+     * @hide
      */
-    private static List<ResolveInfo> getBrowserActionsIntentHandlers(Context context) {
+    @RestrictTo(LIBRARY)
+    @NonNull
+    public static List<ResolveInfo> getBrowserActionsIntentHandlers(@NonNull Context context) {
         Intent intent =
                 new Intent(BrowserActionsIntent.ACTION_BROWSER_ACTIONS_OPEN, Uri.parse(TEST_URL));
         PackageManager pm = context.getPackageManager();
@@ -375,7 +398,7 @@
      * @param context The context requesting for a Browser Actions menu.
      * @param uri The url for Browser Actions menu.
      * @param type The type of the url for context menu to be opened.
-     * @param menuItems List of custom items to add to Browser Actions menu.
+     * @param menuItems List of {@link BrowserActionItem} to add to the fallback menu.
      */
     private static void openFallbackBrowserActionsMenu(
             Context context, Uri uri, int type, List<BrowserActionItem> menuItems) {
@@ -396,16 +419,22 @@
         List<BrowserActionItem> mActions = new ArrayList<>();
         for (int i = 0; i < bundles.size(); i++) {
             Bundle bundle = bundles.get(i);
-            String title = bundle.getString(BrowserActionsIntent.KEY_TITLE);
-            PendingIntent action = bundle.getParcelable(BrowserActionsIntent.KEY_ACTION);
+            String title = bundle.getString(KEY_TITLE);
+            PendingIntent action = bundle.getParcelable(KEY_ACTION);
             @DrawableRes
-            int iconId = bundle.getInt(BrowserActionsIntent.KEY_ICON_ID);
-            if (TextUtils.isEmpty(title) || action == null) {
+            int iconId = bundle.getInt(KEY_ICON_ID);
+            Uri iconUri = bundle.getParcelable(KEY_ICON_URI);
+            if (!TextUtils.isEmpty(title) && action != null) {
+                BrowserActionItem item;
+                if (iconId != 0) {
+                    item = new BrowserActionItem(title, action, iconId);
+                } else {
+                    item = new BrowserActionItem(title, action, iconUri);
+                }
+                mActions.add(item);
+            } else {
                 throw new IllegalArgumentException(
                         "Custom item should contain a non-empty title and non-null intent.");
-            } else {
-                BrowserActionItem item = new BrowserActionItem(title, action, iconId);
-                mActions.add(item);
             }
         }
         return mActions;
@@ -413,11 +442,16 @@
 
     /**
      * Get the package name of the creator application.
+     * <p>
+     * <strong> Note:</strong> This is self-reported and could be untrusted. Intent sender can
+     * modify it to return the package name from a different application.
+     *
      * @param intent The {@link BrowserActionsIntent}.
      * @return The creator package name.
      */
     @SuppressWarnings("deprecation")
-    public static String getCreatorPackageName(Intent intent) {
+    @Nullable
+    public static String getUntrustedCreatorPackageName(@NonNull Intent intent) {
         PendingIntent pendingIntent = intent.getParcelableExtra(BrowserActionsIntent.EXTRA_APP_ID);
         if (pendingIntent != null) {
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
@@ -428,4 +462,15 @@
         }
         return null;
     }
+
+    /**
+     * @deprecated This return value of this method cannot be trusted, it is kept around for
+     *             compatibility. Use {@link #getUntrustedCreatorPackageName}, or an alternative
+     *             method if you rely on the return value.
+     */
+    @Deprecated
+    @Nullable
+    public static String getCreatorPackageName(@NonNull Intent intent) {
+        return getUntrustedCreatorPackageName(intent);
+    }
 }
diff --git a/browser/src/main/java/androidx/browser/browseractions/BrowserServiceFileProvider.java b/browser/src/main/java/androidx/browser/browseractions/BrowserServiceFileProvider.java
new file mode 100644
index 0000000..0d53d78
--- /dev/null
+++ b/browser/src/main/java/androidx/browser/browseractions/BrowserServiceFileProvider.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.browser.browseractions;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
+
+import android.content.ClipData;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.UiThread;
+import androidx.concurrent.futures.ResolvableFuture;
+import androidx.core.content.FileProvider;
+import androidx.core.util.AtomicFile;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * The class to pass images asynchronously between different Browser Services provider and Browser
+ * client.
+ *
+ * Call {@link #saveBitmap} to save the image and {@link #loadBitmap} to read it.
+ * @hide
+ */
+@RestrictTo(LIBRARY)
+public final class BrowserServiceFileProvider extends FileProvider {
+    private static final String TAG = "BrowserServiceFP";
+    private static final String AUTHORITY_SUFFIX = ".image_provider";
+    private static final String CONTENT_SCHEME = "content";
+    private static final String FILE_SUB_DIR = "image_provider";
+    private static final String FILE_SUB_DIR_NAME = "image_provider_images/";
+    private static final String FILE_EXTENSION = ".png";
+    private static final String CLIP_DATA_LABEL = "image_provider_uris";
+    private static final String LAST_CLEANUP_TIME_KEY = "last_cleanup_time";
+
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    static Object sFileCleanupLock = new Object();
+
+    private static class FileCleanupTask extends AsyncTask<Void, Void, Void> {
+        private final Context mAppContext;
+        private static final long IMAGE_RETENTION_DURATION = TimeUnit.DAYS.toMillis(7);
+        private static final long CLEANUP_REQUIRED_TIME_SPAN = TimeUnit.DAYS.toMillis(7);
+        private static final long DELETION_FAILED_REATTEMPT_DURATION = TimeUnit.DAYS.toMillis(1);
+
+        FileCleanupTask(Context context) {
+            super();
+            mAppContext = context.getApplicationContext();
+        }
+
+        @Override
+        protected Void doInBackground(Void... params) {
+            SharedPreferences prefs = mAppContext.getSharedPreferences(
+                    mAppContext.getPackageName() + AUTHORITY_SUFFIX, Context.MODE_PRIVATE);
+            if (!shouldCleanUp(prefs)) return null;
+            synchronized (sFileCleanupLock) {
+                boolean allFilesDeletedSuccessfully = true;
+                File path = new File(mAppContext.getFilesDir(), FILE_SUB_DIR);
+                if (!path.exists()) return null;
+                File[] files = path.listFiles();
+                long retentionDate = System.currentTimeMillis() - IMAGE_RETENTION_DURATION;
+                for (File file : files) {
+                    if (!isImageFile(file)) continue;
+                    long lastModified = file.lastModified();
+                    if (lastModified < retentionDate && !file.delete()) {
+                        Log.e(TAG, "Fail to delete image: " + file.getAbsoluteFile());
+                        allFilesDeletedSuccessfully = false;
+                    }
+                }
+                // If fail to delete some files, kill off clean up task after one day.
+                long lastCleanUpTime;
+                if (allFilesDeletedSuccessfully) {
+                    lastCleanUpTime = System.currentTimeMillis();
+                } else {
+                    lastCleanUpTime = System.currentTimeMillis() - CLEANUP_REQUIRED_TIME_SPAN
+                            + DELETION_FAILED_REATTEMPT_DURATION;
+                }
+                Editor editor = prefs.edit();
+                editor.putLong(LAST_CLEANUP_TIME_KEY, lastCleanUpTime);
+                editor.apply();
+            }
+            return null;
+        }
+
+        private static boolean isImageFile(File file) {
+            String filename = file.getName();
+            return filename.endsWith("." + FILE_EXTENSION);
+        }
+
+        private static boolean shouldCleanUp(SharedPreferences prefs) {
+            long lastCleanup = prefs.getLong(LAST_CLEANUP_TIME_KEY, System.currentTimeMillis());
+            return System.currentTimeMillis() > lastCleanup + CLEANUP_REQUIRED_TIME_SPAN;
+        }
+    }
+
+    private static class FileSaveTask extends AsyncTask<String, Void, Void> {
+        private final Context mAppContext;
+        private final String mFilename;
+        private final Bitmap mBitmap;
+        private final Uri mFileUri;
+        private final ResolvableFuture<Uri> mResultFuture;
+
+        FileSaveTask(Context context, String filename, Bitmap bitmap, Uri fileUri,
+                ResolvableFuture<Uri> resultFuture) {
+            super();
+            mAppContext = context.getApplicationContext();
+            mFilename = filename;
+            mBitmap = bitmap;
+            mFileUri = fileUri;
+            mResultFuture = resultFuture;
+        }
+
+        @Override
+        protected Void doInBackground(String... params) {
+            saveFileIfNeededBlocking();
+            return null;
+        }
+
+        @Override
+        protected void onPostExecute(Void result) {
+            new FileCleanupTask(mAppContext).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
+        }
+
+        private void saveFileIfNeededBlocking() {
+            File path = new File(mAppContext.getFilesDir(), FILE_SUB_DIR);
+            synchronized (sFileCleanupLock) {
+                if (!path.exists() && !path.mkdir()) {
+                    mResultFuture.setException(new IOException("Could not create file directory."));
+                    return;
+                }
+                File img = new File(path, mFilename + FILE_EXTENSION);
+
+                if (img.exists()) {
+                    mResultFuture.set(mFileUri);
+                } else {
+                    saveFileBlocking(img);
+                }
+
+                img.setLastModified(System.currentTimeMillis());
+            }
+        }
+
+        private void saveFileBlocking(File img) {
+            FileOutputStream fOut = null;
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
+                AtomicFile atomicFile = new AtomicFile(img);
+                try {
+                    fOut = atomicFile.startWrite();
+                    mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
+                    fOut.close();
+                    atomicFile.finishWrite(fOut);
+
+                    mResultFuture.set(mFileUri);
+                } catch (IOException e) {
+                    atomicFile.failWrite(fOut);
+
+                    mResultFuture.setException(e);
+                }
+            } else {
+                try {
+                    fOut = new FileOutputStream(img);
+                    mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
+                    fOut.close();
+
+                    mResultFuture.set(mFileUri);
+                } catch (IOException e) {
+                    mResultFuture.setException(e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Request a {@link Uri} used to access the bitmap through the file provider.
+     * @param context The {@link Context} used to generate the uri, save the bitmap and grant the
+     *                read permission.
+     * @param bitmap The {@link Bitmap} to be saved and access through the file provider.
+     * @param name The name of the bitmap.
+     * @param version The version number of the bitmap. Note: This plus the name decides the
+     *                filename of the bitmap. If it matches with existing file, bitmap will skip
+     *                saving.
+     * @return A {@link ResolvableFuture} that will be fulfilled with the uri of the bitmap once
+     *         file writing has completed or an IOException describing the reason for failure.
+     */
+    @UiThread
+    @NonNull
+    public static ResolvableFuture<Uri> saveBitmap(@NonNull Context context, @NonNull Bitmap bitmap,
+            @NonNull String name, int version) {
+        String filename = name + "_" + Integer.toString(version);
+        Uri uri = generateUri(context, filename);
+
+        ResolvableFuture<Uri> result = ResolvableFuture.create();
+        new FileSaveTask(context, filename, bitmap, uri, result)
+                .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+        return result;
+    }
+
+    private static Uri generateUri(Context context, String filename) {
+        String fileName = FILE_SUB_DIR_NAME + filename + FILE_EXTENSION;
+        return new Uri.Builder()
+                .scheme(CONTENT_SCHEME)
+                .authority(context.getPackageName() + AUTHORITY_SUFFIX)
+                .path(fileName)
+                .build();
+    }
+
+    /**
+     * Grant the read permission to a list of {@link Uri} sent through a {@link Intent}.
+     * @param intent The sending Intent which holds a list of Uri.
+     * @param uris A list of Uri generated by saveBitmap(Context, Bitmap, String, int,
+     *             List<String>), if null, nothing will be done.
+     * @param context The context requests to grant the permission.
+     */
+    public static void grantReadPermission(@NonNull Intent intent, @Nullable List<Uri> uris,
+            @NonNull Context context) {
+        if (uris == null || uris.size() == 0) return;
+        ContentResolver resolver = context.getContentResolver();
+        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        ClipData clipData = ClipData.newUri(resolver, CLIP_DATA_LABEL, uris.get(0));
+        for (int i = 1; i < uris.size(); i++) {
+            clipData.addItem(new ClipData.Item(uris.get(i)));
+        }
+        intent.setClipData(clipData);
+    }
+
+    /**
+     * Asynchronously loads a {@link Bitmap} from the uri generated by {@link #saveBitmap}.
+     * @param resolver {@link ContentResolver} to access the Bitmap.
+     * @param uri {@link Uri} pointing to the Bitmap.
+     * @return A {@link ListenableFuture} that will be fulfilled with the Bitmap once the load has
+     *         completed or with an IOException describing the reason for failure.
+     */
+    @NonNull
+    public static ListenableFuture<Bitmap> loadBitmap(@NonNull final ContentResolver resolver,
+            @NonNull final Uri uri) {
+        final ResolvableFuture<Bitmap> result = ResolvableFuture.create();
+
+        AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    ParcelFileDescriptor descriptor = resolver.openFileDescriptor(uri, "r");
+
+                    if (descriptor == null) {
+                        result.setException(new FileNotFoundException());
+                        return;
+                    }
+
+                    FileDescriptor fileDescriptor = descriptor.getFileDescriptor();
+                    Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
+                    descriptor.close();
+
+                    if (bitmap == null) {
+                        result.setException(new IOException("File could not be decoded."));
+                        return;
+                    }
+
+                    result.set(bitmap);
+                } catch (IOException e) {
+                    result.setException(e);
+                }
+            }
+        });
+
+        return result;
+    }
+}
diff --git a/browser/src/main/java/androidx/browser/customtabs/CustomTabsCallback.java b/browser/src/main/java/androidx/browser/customtabs/CustomTabsCallback.java
index 2739bb0..2daff4e 100644
--- a/browser/src/main/java/androidx/browser/customtabs/CustomTabsCallback.java
+++ b/browser/src/main/java/androidx/browser/customtabs/CustomTabsCallback.java
@@ -19,6 +19,8 @@
 import android.net.Uri;
 import android.os.Bundle;
 
+import androidx.browser.customtabs.CustomTabsService.Relation;
+
 /**
  * A callback class for custom tabs client to get messages regarding events in their custom tabs. In
  * the implementation, all callbacks are sent to the UI thread for the client.
@@ -75,7 +77,7 @@
      * purposes.
      *
      * @param callbackName Name of the extra callback.
-     * @param args Arguments for the calback
+     * @param args Arguments for the callback
      */
     public void extraCallback(String callbackName, Bundle args) {}
 
@@ -111,6 +113,6 @@
      * @param result Whether the relation was validated.
      * @param extras Reserved for future use.
      */
-    public void onRelationshipValidationResult(@CustomTabsService.Relation int relation, Uri requestedOrigin,
-                                               boolean result, Bundle extras) {}
+    public void onRelationshipValidationResult(@Relation int relation, Uri requestedOrigin,
+            boolean result, Bundle extras) {}
 }
diff --git a/browser/src/main/java/androidx/browser/customtabs/CustomTabsClient.java b/browser/src/main/java/androidx/browser/customtabs/CustomTabsClient.java
index 42dee4a..794603d 100644
--- a/browser/src/main/java/androidx/browser/customtabs/CustomTabsClient.java
+++ b/browser/src/main/java/androidx/browser/customtabs/CustomTabsClient.java
@@ -33,8 +33,10 @@
 import android.support.customtabs.ICustomTabsService;
 import android.text.TextUtils;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
+import androidx.browser.customtabs.CustomTabsService.Relation;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -77,7 +79,7 @@
     /**
      * Returns the preferred package to use for Custom Tabs, preferring the default VIEW handler.
      *
-     * @see #getPackageName(Context, List, boolean)
+     * @see #getPackageName(Context, List<String>, boolean)
      */
     public static String getPackageName(Context context, @Nullable List<String> packages) {
         return getPackageName(context, packages, false);
@@ -96,8 +98,8 @@
      * @param ignoreDefault If set, the default VIEW handler won't get priority over other browsers.
      * @return The preferred package name for handling Custom Tabs, or <code>null</code>.
      */
-    public static String getPackageName(
-        Context context, @Nullable List<String> packages, boolean ignoreDefault) {
+    public static @Nullable String getPackageName(
+            @NonNull Context context, @Nullable List<String> packages, boolean ignoreDefault) {
         PackageManager pm = context.getPackageManager();
 
         List<String> packageNames = packages == null ? new ArrayList<String>() : packages;
@@ -149,8 +151,8 @@
                 applicationContext.unbindService(this);
             }
 
-           @Override
-           public final void onServiceDisconnected(ComponentName componentName) { }
+            @Override
+            public void onServiceDisconnected(ComponentName componentName) { }
         };
         try {
             return bindCustomTabsService(applicationContext, packageName, connection);
@@ -240,7 +242,7 @@
 
             @Override
             public void onRelationshipValidationResult(
-                    final @CustomTabsService.Relation int relation, final Uri requestedOrigin, final boolean result,
+                    final @Relation int relation, final Uri requestedOrigin, final boolean result,
                     final @Nullable Bundle extras) throws RemoteException {
                 if (callback == null) return;
                 mHandler.post(new Runnable() {
diff --git a/browser/src/main/java/androidx/browser/customtabs/CustomTabsService.java b/browser/src/main/java/androidx/browser/customtabs/CustomTabsService.java
index f07aa8e..80cc6bb 100644
--- a/browser/src/main/java/androidx/browser/customtabs/CustomTabsService.java
+++ b/browser/src/main/java/androidx/browser/customtabs/CustomTabsService.java
@@ -130,7 +130,7 @@
 
         @Override
         public boolean mayLaunchUrl(ICustomTabsCallback callback, Uri url,
-                                    Bundle extras, List<Bundle> otherLikelyBundles) {
+                Bundle extras, List<Bundle> otherLikelyBundles) {
             return CustomTabsService.this.mayLaunchUrl(
                     new CustomTabsSessionToken(callback), url, extras, otherLikelyBundles);
         }
@@ -148,7 +148,7 @@
 
         @Override
         public boolean requestPostMessageChannel(ICustomTabsCallback callback,
-                                                 Uri postMessageOrigin) {
+                Uri postMessageOrigin) {
             return CustomTabsService.this.requestPostMessageChannel(
                     new CustomTabsSessionToken(callback), postMessageOrigin);
         }
@@ -236,7 +236,7 @@
      * @return Whether the call was successful.
      */
     protected abstract boolean mayLaunchUrl(CustomTabsSessionToken sessionToken, Uri url,
-                                            Bundle extras, List<Bundle> otherLikelyBundles);
+            Bundle extras, List<Bundle> otherLikelyBundles);
 
     /**
      * Unsupported commands that may be provided by the implementation.
@@ -264,7 +264,7 @@
      * @return Whether the operation was successful.
      */
     protected abstract boolean updateVisuals(CustomTabsSessionToken sessionToken,
-                                             Bundle bundle);
+            Bundle bundle);
 
     /**
      * Sends a request to create a two way postMessage channel between the client and the browser
@@ -278,7 +278,7 @@
      * asynchronous.
      */
     protected abstract boolean requestPostMessageChannel(CustomTabsSessionToken sessionToken,
-                                                         Uri postMessageOrigin);
+            Uri postMessageOrigin);
 
     /**
      * Sends a postMessage request using the origin communicated via
diff --git a/browser/src/main/java/androidx/browser/customtabs/CustomTabsSession.java b/browser/src/main/java/androidx/browser/customtabs/CustomTabsSession.java
index 3122495..99540f5 100644
--- a/browser/src/main/java/androidx/browser/customtabs/CustomTabsSession.java
+++ b/browser/src/main/java/androidx/browser/customtabs/CustomTabsSession.java
@@ -31,6 +31,8 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.browser.customtabs.CustomTabsService.Relation;
+import androidx.browser.customtabs.CustomTabsService.Result;
 
 import java.util.List;
 
@@ -190,9 +192,9 @@
      * @param message The message that is being sent.
      * @param extras Reserved for future use.
      * @return An integer constant about the postMessage request result. Will return
-      *        {@link CustomTabsService#RESULT_SUCCESS} if successful.
+     *        {@link CustomTabsService#RESULT_SUCCESS} if successful.
      */
-    @CustomTabsService.Result
+    @Result
     public int postMessage(String message, Bundle extras) {
         synchronized (mLock) {
             try {
@@ -223,8 +225,8 @@
      * @param extras Reserved for future use.
      * @return {@code true} if the request has been submitted successfully.
      */
-    public boolean validateRelationship(@CustomTabsService.Relation int relation, @NonNull Uri origin,
-                                        @Nullable Bundle extras) {
+    public boolean validateRelationship(@Relation int relation, @NonNull Uri origin,
+            @Nullable Bundle extras) {
         if (relation < CustomTabsService.RELATION_USE_AS_ORIGIN
                 || relation > CustomTabsService.RELATION_HANDLE_ALL_URLS) {
             return false;
diff --git a/browser/src/main/java/androidx/browser/customtabs/CustomTabsSessionToken.java b/browser/src/main/java/androidx/browser/customtabs/CustomTabsSessionToken.java
index 0783a22..b666adf 100644
--- a/browser/src/main/java/androidx/browser/customtabs/CustomTabsSessionToken.java
+++ b/browser/src/main/java/androidx/browser/customtabs/CustomTabsSessionToken.java
@@ -25,6 +25,7 @@
 import android.util.Log;
 
 import androidx.annotation.NonNull;
+import androidx.browser.customtabs.CustomTabsService.Relation;
 import androidx.core.app.BundleCompat;
 
 /**
@@ -52,7 +53,7 @@
         public void onPostMessage(String message, Bundle extras) {}
 
         @Override
-        public void onRelationshipValidationResult(@CustomTabsService.Relation int relation, Uri requestedOrigin,
+        public void onRelationshipValidationResult(@Relation int relation, Uri requestedOrigin,
                 boolean result, Bundle extras) {}
 
         @Override
@@ -127,8 +128,8 @@
             }
 
             @Override
-            public void onRelationshipValidationResult(@CustomTabsService.Relation int relation, Uri origin,
-                                                       boolean result, Bundle extras) {
+            public void onRelationshipValidationResult(@Relation int relation, Uri origin,
+                    boolean result, Bundle extras) {
                 try {
                     mCallbackBinder.onRelationshipValidationResult(
                             relation, origin, result, extras);
diff --git a/browser/src/main/java/androidx/browser/customtabs/PostMessageService.java b/browser/src/main/java/androidx/browser/customtabs/PostMessageService.java
index 3764d65..ec8e1d4 100644
--- a/browser/src/main/java/androidx/browser/customtabs/PostMessageService.java
+++ b/browser/src/main/java/androidx/browser/customtabs/PostMessageService.java
@@ -38,7 +38,7 @@
 
         @Override
         public void onPostMessage(ICustomTabsCallback callback,
-                                  String message, Bundle extras) throws RemoteException {
+                String message, Bundle extras) throws RemoteException {
             callback.onPostMessage(message, extras);
         }
     };
diff --git a/browser/src/main/res/layout/browser_actions_context_menu_page.xml b/browser/src/main/res/layout/browser_actions_context_menu_page.xml
index 7720f91..696f2ff 100644
--- a/browser/src/main/res/layout/browser_actions_context_menu_page.xml
+++ b/browser/src/main/res/layout/browser_actions_context_menu_page.xml
@@ -1,7 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
+<!-- Copyright 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License
+-->
+
 <androidx.browser.browseractions.BrowserActionsFallbackMenuView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
diff --git a/browser/src/main/res/layout/browser_actions_context_menu_row.xml b/browser/src/main/res/layout/browser_actions_context_menu_row.xml
index d13e48f..91ccd11 100644
--- a/browser/src/main/res/layout/browser_actions_context_menu_row.xml
+++ b/browser/src/main/res/layout/browser_actions_context_menu_row.xml
@@ -1,7 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
+<!-- Copyright 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License
+-->
+
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="horizontal"
@@ -9,15 +21,7 @@
     android:layout_height="wrap_content"
     android:paddingStart="15dp"
     android:paddingEnd="15dp"
-    android:minHeight="40dp">
-    <ImageView
-        android:id="@+id/browser_actions_menu_item_icon"
-        android:layout_width="20dp"
-        android:layout_height="match_parent"
-        android:paddingTop="10dp"
-        android:paddingBottom="10dp"
-        android:scaleType="centerInside"
-        android:contentDescription="@null" />
+    android:minHeight="48dp">
     <TextView
         android:id="@+id/browser_actions_menu_item_text"
         android:layout_width="0dp"
@@ -27,4 +31,12 @@
         android:layout_weight="1"
         android:textSize="15sp"
         android:textColor="@color/browser_actions_text_color" />
+    <ImageView
+            android:id="@+id/browser_actions_menu_item_icon"
+            android:layout_width="20dp"
+            android:layout_height="match_parent"
+            android:paddingTop="8dp"
+            android:paddingBottom="8dp"
+            android:scaleType="centerInside"
+            android:contentDescription="@null" />
 </LinearLayout>
diff --git a/browser/src/main/res/values/colors.xml b/browser/src/main/res/values/colors.xml
index 3086991..f21807f 100644
--- a/browser/src/main/res/values/colors.xml
+++ b/browser/src/main/res/values/colors.xml
@@ -1,7 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
+<!-- Copyright 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License
+-->
 
 <resources>
     <color name="browser_actions_text_color">#DE000000</color>
diff --git a/browser/src/main/res/values/dimens.xml b/browser/src/main/res/values/dimens.xml
index b90750a..463fa1f 100644
--- a/browser/src/main/res/values/dimens.xml
+++ b/browser/src/main/res/values/dimens.xml
@@ -1,7 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
+<!-- Copyright 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License
+-->
 
 <resources>
     <!-- Browser Actions Context Menu Dimensions -->
diff --git a/browser/src/main/res/values/strings.xml b/browser/src/main/res/values/strings.xml
new file mode 100644
index 0000000..b4c9924
--- /dev/null
+++ b/browser/src/main/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License
+-->
+
+<resources>
+    <string name="fallback_menu_item_open_in_browser">Open in browser</string>
+    <string name="fallback_menu_item_copy_link">Copy link</string>
+    <string name="fallback_menu_item_share_link">Share link</string>
+    <string name="copy_toast_msg">Link copied to clipboard</string>
+</resources>
\ No newline at end of file
diff --git a/browser/src/main/res/xml/image_share_filepaths.xml b/browser/src/main/res/xml/image_share_filepaths.xml
new file mode 100644
index 0000000..123fde9
--- /dev/null
+++ b/browser/src/main/res/xml/image_share_filepaths.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License
+-->
+
+<paths>
+    <files-path path="image_provider/" name="image_provider_images" />
+</paths>
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
index d663201..0de6c44 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
@@ -31,7 +31,7 @@
     val ASYNCLAYOUTINFLATER = Version("1.0.0")
     val BENCHMARK = Version("1.0.0-alpha01")
     val BIOMETRIC = Version("1.0.0-alpha04")
-    val BROWSER = Version("1.0.0")
+    val BROWSER = Version("1.1.0-alpha01")
     val CAR = Version("1.0.0-alpha6")
     val CAR_CLUSTER = Version("1.0.0-alpha5")
     val CAR_MODERATOR = Version("1.0.0-alpha1")
@@ -59,7 +59,7 @@
     val LEANBACK_PREFERENCE = Version("1.1.0-alpha01")
     val LEGACY = Version("1.0.0")
     val LOCALBROADCASTMANAGER = Version("1.1.0-alpha01")
-    val LIFECYCLE = Version("2.1.0-alpha02")
+    val LIFECYCLE = Version("2.1.0-alpha03")
     val LIFECYCLES_SAVEDSTATE = Version("1.0.0-alpha01")
     val LOADER = Version("1.1.0-beta01")
     val MEDIA = Version("1.1.0-alpha01")
@@ -67,7 +67,7 @@
     val MEDIA2_EXOPLAYER = Version("1.0.0-alpha01")
     val MEDIA2_WIDGET = Version("1.0.0-alpha07")
     val MEDIAROUTER = Version("1.1.0-alpha01")
-    val NAVIGATION = Version("1.0.0-beta01")
+    val NAVIGATION = Version("1.0.0-beta02")
     val NAVIGATION_TESTING = Version("1.0.0-alpha08") // Unpublished
     val PAGING = Version("2.2.0-alpha01")
     val PALETTE = Version("1.1.0-alpha01")
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.java b/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.java
deleted file mode 100644
index cb3b216..0000000
--- a/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.fragment.app;
-
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.test.EmptyFragmentTestActivity;
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
-import androidx.lifecycle.OnLifecycleEvent;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.ActivityTestRule;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-public class DialogFragmentTest {
-    @Rule
-    public final ActivityTestRule<EmptyFragmentTestActivity> mActivityTestRule =
-            new ActivityTestRule<>(EmptyFragmentTestActivity.class);
-
-    @Test
-    public void testDialogFragmentShows() {
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        TestDialogFragment fragment = new TestDialogFragment();
-        fragment.show(mActivityTestRule.getActivity().getSupportFragmentManager(), null);
-
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        assertWithMessage("Dialog was null")
-                .that(fragment.getDialog())
-                .isNotNull();
-        assertWithMessage("Dialog was not being shown")
-                .that(fragment.getDialog().isShowing())
-                .isTrue();
-    }
-
-    @Test
-    public void testDialogFragmentShowsNow() throws Throwable {
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        final TestDialogFragment fragment = new TestDialogFragment();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                fragment.showNow(mActivityTestRule.getActivity().getSupportFragmentManager(),
-                        null);
-            }
-        });
-
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        assertWithMessage("Dialog was null")
-                .that(fragment.getDialog())
-                .isNotNull();
-        assertWithMessage("Dialog was not being shown")
-                .that(fragment.getDialog().isShowing())
-                .isTrue();
-
-        final boolean[] dialogIsNonNull = new boolean[1];
-        final boolean[] isShowing = new boolean[1];
-        final int[] onDismissCalledCount = new int[1];
-        final CountDownLatch countDownLatch = new CountDownLatch(2);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                fragment.getLifecycle().addObserver(new LifecycleObserver() {
-                    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
-                    public void onStop() {
-                        Dialog dialog = fragment.getDialog();
-                        dialogIsNonNull[0] = dialog != null;
-                        isShowing[0] = dialog != null && dialog.isShowing();
-                        countDownLatch.countDown();
-                    }
-
-                    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
-                    public void onDestroy() {
-                        onDismissCalledCount[0] = fragment.onDismissCalledCount;
-                        countDownLatch.countDown();
-                    }
-                });
-            }
-        });
-
-        mActivityTestRule.finishActivity();
-
-        countDownLatch.await(1, TimeUnit.SECONDS);
-        assertWithMessage("onDismiss() should be called before onDestroy()")
-                .that(onDismissCalledCount[0])
-                .isEqualTo(1);
-        assertWithMessage("Dialog should not be null in onStop()")
-                .that(dialogIsNonNull[0])
-                .isTrue();
-        assertWithMessage("Dialog should still be showing in onStop() "
-                + "during the normal lifecycle")
-                .that(isShowing[0])
-                .isTrue();
-    }
-
-    @Test
-    public void testDialogFragmentDismiss() throws Throwable {
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        final TestDialogFragment fragment = new TestDialogFragment();
-        fragment.show(mActivityTestRule.getActivity().getSupportFragmentManager(), null);
-
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        assertWithMessage("Dialog was null")
-                .that(fragment.getDialog())
-                .isNotNull();
-        assertWithMessage("Dialog was not being shown")
-                .that(fragment.getDialog().isShowing())
-                .isTrue();
-
-        final boolean[] dialogIsNonNull = new boolean[1];
-        final boolean[] isShowing = new boolean[1];
-        final CountDownLatch countDownLatch = new CountDownLatch(1);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                fragment.getLifecycle().addObserver(new LifecycleObserver() {
-                    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
-                    public void onStop() {
-                        Dialog dialog = fragment.getDialog();
-                        dialogIsNonNull[0] = dialog != null;
-                        isShowing[0] = dialog != null && dialog.isShowing();
-                        countDownLatch.countDown();
-                    }
-                });
-            }
-        });
-
-        final CountDownLatch dismissLatch = new CountDownLatch(1);
-        fragment.setDestroyViewCallback(new TestDialogFragment.OnDestroyViewCallback() {
-            @Override
-            public void onDestroyView(TestDialogFragment fragment) {
-                dismissLatch.countDown();
-            }
-        });
-
-        fragment.dismiss();
-
-        countDownLatch.await(1, TimeUnit.SECONDS);
-
-        assertWithMessage("Dialog should not be null in onStop()")
-                .that(dialogIsNonNull[0])
-                .isTrue();
-        assertWithMessage("Dialog should not be showing in onStop() "
-                + "when manually dismissed")
-                .that(isShowing[0])
-                .isFalse();
-
-        // Wait for the DialogFragment's onDestroyView to be called which is where the Dialog
-        // gets null'ed out
-        dismissLatch.await();
-
-        assertWithMessage("Dialog should be null after dismiss()")
-                .that(fragment.getDialog())
-                .isNull();
-    }
-
-    @Test
-    public void testDialogFragmentDismissBeforeOnDestroy() throws Throwable {
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        final TestDialogFragment fragment = new TestDialogFragment();
-        fragment.show(mActivityTestRule.getActivity().getSupportFragmentManager(), null);
-
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        final int[] onDismissCalledCount = new int[1];
-        final CountDownLatch countDownLatch = new CountDownLatch(1);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                fragment.getLifecycle().addObserver(new LifecycleObserver() {
-                    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
-                    public void onDestroy() {
-                        onDismissCalledCount[0] = fragment.onDismissCalledCount;
-                        countDownLatch.countDown();
-                    }
-                });
-            }
-        });
-
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                fragment.dismiss();
-            }
-        });
-
-        countDownLatch.await(1, TimeUnit.SECONDS);
-
-        assertWithMessage("onDismiss() should be called only once before onDestroy()")
-                .that(onDismissCalledCount[0])
-                .isEqualTo(1);
-    }
-
-    public static class TestDialogFragment extends DialogFragment {
-
-        public interface OnDestroyViewCallback {
-            void onDestroyView(TestDialogFragment fragment);
-        }
-
-        public int onDismissCalledCount = 0;
-
-        private @Nullable OnDestroyViewCallback mDestroyViewCallback = null;
-
-        public void setDestroyViewCallback(OnDestroyViewCallback callback) {
-            mDestroyViewCallback = callback;
-        }
-
-        @NonNull
-        @Override
-        public Dialog onCreateDialog(Bundle savedInstanceState) {
-            return new AlertDialog.Builder(getContext())
-                    .setTitle("Test")
-                    .setMessage("Message")
-                    .setPositiveButton("Button", null)
-                    .create();
-        }
-
-        @Override
-        public void onDismiss(@NonNull DialogInterface dialog) {
-            super.onDismiss(dialog);
-            onDismissCalledCount++;
-        }
-
-        @Override
-        public void onDestroyView() {
-            super.onDestroyView();
-            if (mDestroyViewCallback != null) {
-                mDestroyViewCallback.onDestroyView(this);
-            }
-        }
-    }
-}
-
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.kt b/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.kt
new file mode 100644
index 0000000..8b7b33d
--- /dev/null
+++ b/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.kt
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.fragment.app
+
+import android.app.AlertDialog
+import android.app.Dialog
+import android.content.DialogInterface
+import android.os.Bundle
+import android.os.Looper
+import androidx.fragment.app.test.EmptyFragmentTestActivity
+import androidx.lifecycle.GenericLifecycleObserver
+import androidx.lifecycle.Lifecycle
+import androidx.test.annotation.UiThreadTest
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.rule.ActivityTestRule
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class DialogFragmentTest {
+    @get:Rule
+    val activityTestRule = ActivityTestRule(EmptyFragmentTestActivity::class.java)
+
+    @Test
+    fun testDialogFragmentShows() {
+        val fragment = TestDialogFragment()
+        fragment.show(activityTestRule.activity.supportFragmentManager, null)
+        activityTestRule.runOnUiThread {
+            activityTestRule.activity.supportFragmentManager.executePendingTransactions()
+        }
+
+        assertWithMessage("Dialog was not being shown")
+            .that(fragment.dialog?.isShowing)
+            .isTrue()
+    }
+
+    @UiThreadTest
+    @Test
+    fun testDialogFragmentShowsNow() {
+        val fragment = TestDialogFragment()
+        fragment.showNow(activityTestRule.activity.supportFragmentManager, null)
+
+        assertWithMessage("Dialog was not being shown")
+            .that(fragment.dialog?.isShowing)
+            .isTrue()
+    }
+
+    @Test
+    fun testDialogFragmentDismissOnFinish() {
+        val fragment = TestDialogFragment()
+        activityTestRule.runOnUiThread {
+            fragment.showNow(activityTestRule.activity.supportFragmentManager, null)
+        }
+
+        assertWithMessage("Dialog was not being shown")
+            .that(fragment.dialog?.isShowing)
+            .isTrue()
+
+        var dialogIsNonNull = false
+        var isShowing = false
+        var onDismissCalledCount = 0
+        val countDownLatch = CountDownLatch(3)
+        activityTestRule.runOnUiThread {
+            fragment.lifecycle.addObserver(GenericLifecycleObserver { _, event ->
+                if (event == Lifecycle.Event.ON_STOP) {
+                    val dialog = fragment.dialog
+                    dialogIsNonNull = dialog != null
+                    isShowing = dialog != null && dialog.isShowing
+                    countDownLatch.countDown()
+                } else if (event == Lifecycle.Event.ON_DESTROY) {
+                    onDismissCalledCount = fragment.onDismissCalledCount
+                    countDownLatch.countDown()
+                }
+            })
+        }
+        var dismissOnMainThread = false
+        var dismissCalled = false
+        fragment.dismissCallback = {
+            dismissCalled = true
+            dismissOnMainThread = Looper.myLooper() == Looper.getMainLooper()
+            countDownLatch.countDown()
+        }
+
+        activityTestRule.finishActivity()
+
+        countDownLatch.await(1, TimeUnit.SECONDS)
+
+        assertWithMessage("Dialog should be dismissed")
+            .that(dismissCalled)
+            .isTrue()
+        assertWithMessage("Dismiss should always be called on the main thread")
+            .that(dismissOnMainThread)
+            .isTrue()
+        assertWithMessage("onDismiss() should be called before onDestroy()")
+            .that(onDismissCalledCount)
+            .isEqualTo(1)
+        assertWithMessage("Dialog should not be null in onStop()")
+            .that(dialogIsNonNull)
+            .isTrue()
+        assertWithMessage("Dialog should still be showing in onStop() during the normal lifecycle")
+            .that(isShowing)
+            .isTrue()
+    }
+
+    @Test
+    fun testDialogFragmentDismiss() {
+        val fragment = TestDialogFragment()
+        activityTestRule.runOnUiThread {
+            fragment.showNow(activityTestRule.activity.supportFragmentManager, null)
+        }
+
+        assertWithMessage("Dialog was not being shown")
+            .that(fragment.dialog?.isShowing)
+            .isTrue()
+
+        var dialogIsNonNull = false
+        var isShowing = false
+        var onDismissCalledCount = 0
+        val countDownLatch = CountDownLatch(3)
+        activityTestRule.runOnUiThread {
+            fragment.lifecycle.addObserver(GenericLifecycleObserver { _, event ->
+                if (event == Lifecycle.Event.ON_STOP) {
+                    val dialog = fragment.dialog
+                    dialogIsNonNull = dialog != null
+                    isShowing = dialog != null && dialog.isShowing
+                    countDownLatch.countDown()
+                } else if (event == Lifecycle.Event.ON_DESTROY) {
+                    onDismissCalledCount = fragment.onDismissCalledCount
+                    countDownLatch.countDown()
+                }
+            })
+        }
+        var dismissOnMainThread = false
+        var dismissCalled = false
+        fragment.dismissCallback = {
+            dismissCalled = true
+            dismissOnMainThread = Looper.myLooper() == Looper.getMainLooper()
+            countDownLatch.countDown()
+        }
+
+        fragment.dismiss()
+
+        countDownLatch.await(1, TimeUnit.SECONDS)
+
+        assertWithMessage("Dialog should be dismissed")
+            .that(dismissCalled)
+            .isTrue()
+        assertWithMessage("Dismiss should always be called on the main thread")
+            .that(dismissOnMainThread)
+            .isTrue()
+        assertWithMessage("onDismiss() should be called before onDestroy()")
+            .that(onDismissCalledCount)
+            .isEqualTo(1)
+        assertWithMessage("Dialog should not be null in onStop()")
+            .that(dialogIsNonNull)
+            .isTrue()
+        assertWithMessage("Dialog should not be showing in onStop() when manually dismissed")
+            .that(isShowing)
+            .isFalse()
+
+        assertWithMessage("Dialog should be null after dismiss()")
+            .that(fragment.dialog)
+            .isNull()
+    }
+
+    @Test
+    fun testDialogFragmentDismissBeforeOnDestroy() {
+        val fragment = TestDialogFragment()
+        activityTestRule.runOnUiThread {
+            fragment.showNow(activityTestRule.activity.supportFragmentManager, null)
+        }
+
+        var onDismissCalledCount = 0
+        val countDownLatch = CountDownLatch(1)
+        activityTestRule.runOnUiThread {
+            fragment.lifecycle.addObserver(GenericLifecycleObserver { _, event ->
+                if (event == Lifecycle.Event.ON_DESTROY) {
+                    onDismissCalledCount = fragment.onDismissCalledCount
+                    countDownLatch.countDown()
+                }
+            })
+            // Now dismiss the Fragment
+            fragment.dismiss()
+        }
+
+        countDownLatch.await(1, TimeUnit.SECONDS)
+
+        assertWithMessage("onDismiss() should be called only once before onDestroy()")
+            .that(onDismissCalledCount)
+            .isEqualTo(1)
+    }
+
+    class TestDialogFragment : DialogFragment() {
+
+        var onDismissCalledCount = 0
+        var dismissCallback: () -> Unit = {}
+
+        override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+            return AlertDialog.Builder(context)
+                .setTitle("Test")
+                .setMessage("Message")
+                .setPositiveButton("Button", null)
+                .create()
+        }
+
+        override fun onDismiss(dialog: DialogInterface) {
+            super.onDismiss(dialog)
+            onDismissCalledCount++
+            dismissCallback.invoke()
+        }
+    }
+}
diff --git a/fragment/src/main/java/androidx/fragment/app/DialogFragment.java b/fragment/src/main/java/androidx/fragment/app/DialogFragment.java
index 51df134..b1642aa 100644
--- a/fragment/src/main/java/androidx/fragment/app/DialogFragment.java
+++ b/fragment/src/main/java/androidx/fragment/app/DialogFragment.java
@@ -23,6 +23,8 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -87,6 +89,15 @@
     private static final String SAVED_SHOWS_DIALOG = "android:showsDialog";
     private static final String SAVED_BACK_STACK_ID = "android:backStackId";
 
+    private Handler mHandler;
+    private Runnable mDismissRunnable = new Runnable() {
+        @Override
+        public void run() {
+            if (mDialog != null) {
+                onDismiss(mDialog);
+            }
+        }
+    };
     int mStyle = STYLE_NORMAL;
     int mTheme = 0;
     boolean mCancelable = true;
@@ -208,7 +219,20 @@
         mDismissed = true;
         mShownByMe = false;
         if (mDialog != null) {
+            // Instead of waiting for a posted onDismiss(), null out
+            // the listener and call onDismiss() manually to ensure
+            // that the callback happens before onDestroy()
+            mDialog.setOnDismissListener(null);
             mDialog.dismiss();
+            // onDismiss() is always called on the main thread, so
+            // we mimic that behavior here. The difference here is that
+            // we don't post the message to ensure that the onDismiss()
+            // callback still happens before onDestroy()
+            if (Looper.myLooper() == mHandler.getLooper()) {
+                onDismiss(mDialog);
+            } else {
+                mHandler.post(mDismissRunnable);
+            }
         }
         mViewDestroyed = true;
         if (mBackStackId >= 0) {
@@ -330,6 +354,8 @@
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        // This assumes that onCreate() is being called on the main thread
+        mHandler = new Handler();
 
         mShowsDialog = mContainerId == 0;
 
@@ -504,12 +530,14 @@
             // the dialog -- we don't want this to cause the fragment to
             // actually be removed.
             mViewDestroyed = true;
-            if (mDialog.isShowing()) {
-                // Instead of waiting for a posted onDismiss(), null out
-                // the listener and call onDismiss() manually to ensure
-                // that the callback happens before onDestroy()
-                mDialog.setOnDismissListener(null);
-                mDialog.dismiss();
+            // Instead of waiting for a posted onDismiss(), null out
+            // the listener and call onDismiss() manually to ensure
+            // that the callback happens before onDestroy()
+            mDialog.setOnDismissListener(null);
+            mDialog.dismiss();
+            if (!mDismissed) {
+                // Don't send a second onDismiss() callback if we've already
+                // dismissed the dialog manually in dismissInternal()
                 onDismiss(mDialog);
             }
             mDialog = null;
diff --git a/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackPreferenceFragmentCompat.java b/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackPreferenceFragmentCompat.java
index 78c282b..e2e4980 100644
--- a/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackPreferenceFragmentCompat.java
+++ b/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackPreferenceFragmentCompat.java
@@ -32,15 +32,12 @@
  * <p>The following sample code shows a simple leanback preference fragment that is
  * populated from a resource.  The resource it loads is:</p>
  *
- * {@sample frameworks/support/samples/SupportPreferenceDemos/src/main/res/xml/preferences.xml
- * preferences}
+ * {@sample frameworks/support/samples/SupportPreferenceDemos/src/main/res/xml/preferences.xml preferences}
  *
  * <p>The fragment needs only to implement {@link #onCreatePreferences(Bundle, String)} to populate
  * the list of preference objects:</p>
  *
- * {@sample frameworks/support/samples/SupportPreferenceDemos/src/main/java/com/example/android/supportpreference/FragmentSupportPreferencesLeanback.java
- *      support_fragment_leanback}
- * support_fragment_leanback}
+ * {@sample frameworks/support/samples/SupportPreferenceDemos/src/main/java/com/example/androidx/preference/LeanbackPreferences.java leanback_preferences}
  */
 public abstract class LeanbackPreferenceFragmentCompat extends
         BaseLeanbackPreferenceFragmentCompat {
diff --git a/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackSettingsFragmentCompat.java b/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackSettingsFragmentCompat.java
index 9f34a33..69e00b0 100644
--- a/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackSettingsFragmentCompat.java
+++ b/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackSettingsFragmentCompat.java
@@ -39,8 +39,7 @@
  * <p>The following sample code shows a simple leanback preference fragment that is
  * populated from a resource.  The resource it loads is:</p>
  *
- * {@sample frameworks/support/samples/SupportPreferenceDemos/src/main/res/xml/preferences.xml
- * preferences}
+ * {@sample frameworks/support/samples/SupportPreferenceDemos/src/main/res/xml/preferences.xml preferences}
  *
  * <p>The sample implements
  * {@link PreferenceFragmentCompat.OnPreferenceStartFragmentCallback#onPreferenceStartFragment(
@@ -49,8 +48,7 @@
  * PreferenceFragmentCompat, PreferenceScreen)},
  * and {@link #onPreferenceStartInitialScreen()}:</p>
  *
- * {@sample frameworks/support/samples/SupportPreferenceDemos/src/main/java/com/example/android/supportpreference/FragmentSupportPreferencesLeanback.java
- *      support_fragment_leanback}
+ * {@sample frameworks/support/samples/SupportPreferenceDemos/src/main/java/com/example/androidx/preference/LeanbackPreferences.java leanback_preferences}
  */
 public abstract class LeanbackSettingsFragmentCompat extends Fragment
         implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback,
diff --git a/lifecycle/common-java8/api/2.1.0-alpha03.txt b/lifecycle/common-java8/api/2.1.0-alpha03.txt
new file mode 100644
index 0000000..498d3a9
--- /dev/null
+++ b/lifecycle/common-java8/api/2.1.0-alpha03.txt
@@ -0,0 +1,14 @@
+// Signature format: 3.0
+package androidx.lifecycle {
+
+  public interface DefaultLifecycleObserver extends androidx.lifecycle.LifecycleObserver androidx.lifecycle.LifecycleObserver {
+    method public default void onCreate(androidx.lifecycle.LifecycleOwner);
+    method public default void onDestroy(androidx.lifecycle.LifecycleOwner);
+    method public default void onPause(androidx.lifecycle.LifecycleOwner);
+    method public default void onResume(androidx.lifecycle.LifecycleOwner);
+    method public default void onStart(androidx.lifecycle.LifecycleOwner);
+    method public default void onStop(androidx.lifecycle.LifecycleOwner);
+  }
+
+}
+
diff --git a/lifecycle/common/api/2.1.0-alpha03.txt b/lifecycle/common/api/2.1.0-alpha03.txt
new file mode 100644
index 0000000..f23b5eb
--- /dev/null
+++ b/lifecycle/common/api/2.1.0-alpha03.txt
@@ -0,0 +1,46 @@
+// Signature format: 3.0
+package androidx.lifecycle {
+
+  public abstract class Lifecycle {
+    ctor public Lifecycle();
+    method @MainThread public abstract void addObserver(androidx.lifecycle.LifecycleObserver);
+    method @MainThread public abstract androidx.lifecycle.Lifecycle.State getCurrentState();
+    method @MainThread public abstract void removeObserver(androidx.lifecycle.LifecycleObserver);
+  }
+
+  public enum Lifecycle.Event {
+    enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_ANY;
+    enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_CREATE;
+    enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_DESTROY;
+    enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_PAUSE;
+    enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_RESUME;
+    enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_START;
+    enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_STOP;
+  }
+
+  public enum Lifecycle.State {
+    method public boolean isAtLeast(androidx.lifecycle.Lifecycle.State);
+    enum_constant public static final androidx.lifecycle.Lifecycle.State CREATED;
+    enum_constant public static final androidx.lifecycle.Lifecycle.State DESTROYED;
+    enum_constant public static final androidx.lifecycle.Lifecycle.State INITIALIZED;
+    enum_constant public static final androidx.lifecycle.Lifecycle.State RESUMED;
+    enum_constant public static final androidx.lifecycle.Lifecycle.State STARTED;
+  }
+
+  public interface LifecycleEventObserver extends androidx.lifecycle.LifecycleObserver {
+    method public void onStateChanged(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.Event);
+  }
+
+  public interface LifecycleObserver {
+  }
+
+  public interface LifecycleOwner {
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+  }
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface OnLifecycleEvent {
+    method public abstract androidx.lifecycle.Lifecycle.Event value();
+  }
+
+}
+
diff --git a/lifecycle/extensions/api/2.1.0-alpha03.txt b/lifecycle/extensions/api/2.1.0-alpha03.txt
new file mode 100644
index 0000000..c85f1ab
--- /dev/null
+++ b/lifecycle/extensions/api/2.1.0-alpha03.txt
@@ -0,0 +1,22 @@
+// Signature format: 3.0
+package androidx.lifecycle {
+
+  public class ViewModelProviders {
+    ctor @Deprecated public ViewModelProviders();
+    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment);
+    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity);
+    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment, androidx.lifecycle.ViewModelProvider.Factory?);
+    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity, androidx.lifecycle.ViewModelProvider.Factory?);
+  }
+
+  @Deprecated public static class ViewModelProviders.DefaultFactory extends androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory {
+    ctor @Deprecated public ViewModelProviders.DefaultFactory(android.app.Application);
+  }
+
+  @Deprecated public class ViewModelStores {
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelStore of(androidx.fragment.app.FragmentActivity);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelStore of(androidx.fragment.app.Fragment);
+  }
+
+}
+
diff --git a/lifecycle/extensions/api/res-2.1.0-alpha03.txt b/lifecycle/extensions/api/res-2.1.0-alpha03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lifecycle/extensions/api/res-2.1.0-alpha03.txt
diff --git a/lifecycle/livedata-core/api/2.1.0-alpha03.txt b/lifecycle/livedata-core/api/2.1.0-alpha03.txt
new file mode 100644
index 0000000..f0db7db
--- /dev/null
+++ b/lifecycle/livedata-core/api/2.1.0-alpha03.txt
@@ -0,0 +1,32 @@
+// Signature format: 3.0
+package androidx.lifecycle {
+
+  public abstract class LiveData<T> {
+    ctor public LiveData(T!);
+    ctor public LiveData();
+    method public T? getValue();
+    method public boolean hasActiveObservers();
+    method public boolean hasObservers();
+    method @MainThread public void observe(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Observer<? super T>);
+    method @MainThread public void observeForever(androidx.lifecycle.Observer<? super T>);
+    method protected void onActive();
+    method protected void onInactive();
+    method protected void postValue(T!);
+    method @MainThread public void removeObserver(androidx.lifecycle.Observer<? super T>);
+    method @MainThread public void removeObservers(androidx.lifecycle.LifecycleOwner);
+    method @MainThread protected void setValue(T!);
+  }
+
+  public class MutableLiveData<T> extends androidx.lifecycle.LiveData<T> {
+    ctor public MutableLiveData(T!);
+    ctor public MutableLiveData();
+    method public void postValue(T!);
+    method public void setValue(T!);
+  }
+
+  public interface Observer<T> {
+    method public void onChanged(T!);
+  }
+
+}
+
diff --git a/lifecycle/livedata-core/api/res-2.1.0-alpha03.txt b/lifecycle/livedata-core/api/res-2.1.0-alpha03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lifecycle/livedata-core/api/res-2.1.0-alpha03.txt
diff --git a/lifecycle/livedata-core/ktx/api/2.1.0-alpha03.txt b/lifecycle/livedata-core/ktx/api/2.1.0-alpha03.txt
new file mode 100644
index 0000000..861a341
--- /dev/null
+++ b/lifecycle/livedata-core/ktx/api/2.1.0-alpha03.txt
@@ -0,0 +1,10 @@
+// Signature format: 3.0
+package androidx.lifecycle {
+
+  public final class LiveDataKt {
+    ctor public LiveDataKt();
+    method @MainThread public static inline <T> androidx.lifecycle.Observer<T> observe(androidx.lifecycle.LiveData<T>, androidx.lifecycle.LifecycleOwner owner, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged);
+  }
+
+}
+
diff --git a/lifecycle/livedata-core/ktx/api/res-2.1.0-alpha03.txt b/lifecycle/livedata-core/ktx/api/res-2.1.0-alpha03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lifecycle/livedata-core/ktx/api/res-2.1.0-alpha03.txt
diff --git a/lifecycle/livedata/api/2.1.0-alpha03.txt b/lifecycle/livedata/api/2.1.0-alpha03.txt
new file mode 100644
index 0000000..2f5616b
--- /dev/null
+++ b/lifecycle/livedata/api/2.1.0-alpha03.txt
@@ -0,0 +1,17 @@
+// Signature format: 3.0
+package androidx.lifecycle {
+
+  public class MediatorLiveData<T> extends androidx.lifecycle.MutableLiveData<T> {
+    ctor public MediatorLiveData();
+    method @MainThread public <S> void addSource(androidx.lifecycle.LiveData<S>, androidx.lifecycle.Observer<? super S>);
+    method @MainThread public <S> void removeSource(androidx.lifecycle.LiveData<S>);
+  }
+
+  public class Transformations {
+    method @MainThread public static <X> androidx.lifecycle.LiveData<X> distinctUntilChanged(androidx.lifecycle.LiveData<X>);
+    method @MainThread public static <X, Y> androidx.lifecycle.LiveData<Y> map(androidx.lifecycle.LiveData<X>, androidx.arch.core.util.Function<X,Y>);
+    method @MainThread public static <X, Y> androidx.lifecycle.LiveData<Y> switchMap(androidx.lifecycle.LiveData<X>, androidx.arch.core.util.Function<X,androidx.lifecycle.LiveData<Y>>);
+  }
+
+}
+
diff --git a/lifecycle/livedata/api/res-2.1.0-alpha03.txt b/lifecycle/livedata/api/res-2.1.0-alpha03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lifecycle/livedata/api/res-2.1.0-alpha03.txt
diff --git a/lifecycle/livedata/ktx/api/2.1.0-alpha03.txt b/lifecycle/livedata/ktx/api/2.1.0-alpha03.txt
new file mode 100644
index 0000000..a21c943
--- /dev/null
+++ b/lifecycle/livedata/ktx/api/2.1.0-alpha03.txt
@@ -0,0 +1,12 @@
+// Signature format: 3.0
+package androidx.lifecycle {
+
+  public final class TransformationsKt {
+    ctor public TransformationsKt();
+    method public static inline <X> androidx.lifecycle.LiveData<X> distinctUntilChanged(androidx.lifecycle.LiveData<X>);
+    method public static inline <X, Y> androidx.lifecycle.LiveData<Y> map(androidx.lifecycle.LiveData<X>, kotlin.jvm.functions.Function1<? super X,? extends Y> transform);
+    method public static inline <X, Y> androidx.lifecycle.LiveData<Y> switchMap(androidx.lifecycle.LiveData<X>, kotlin.jvm.functions.Function1<? super X,? extends androidx.lifecycle.LiveData<Y>> transform);
+  }
+
+}
+
diff --git a/lifecycle/livedata/ktx/api/res-2.1.0-alpha03.txt b/lifecycle/livedata/ktx/api/res-2.1.0-alpha03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lifecycle/livedata/ktx/api/res-2.1.0-alpha03.txt
diff --git a/lifecycle/process/api/2.1.0-alpha03.txt b/lifecycle/process/api/2.1.0-alpha03.txt
new file mode 100644
index 0000000..beea619
--- /dev/null
+++ b/lifecycle/process/api/2.1.0-alpha03.txt
@@ -0,0 +1,10 @@
+// Signature format: 3.0
+package androidx.lifecycle {
+
+  public class ProcessLifecycleOwner implements androidx.lifecycle.LifecycleOwner {
+    method public static androidx.lifecycle.LifecycleOwner get();
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+  }
+
+}
+
diff --git a/lifecycle/process/api/res-2.1.0-alpha03.txt b/lifecycle/process/api/res-2.1.0-alpha03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lifecycle/process/api/res-2.1.0-alpha03.txt
diff --git a/lifecycle/reactivestreams/api/2.1.0-alpha03.txt b/lifecycle/reactivestreams/api/2.1.0-alpha03.txt
new file mode 100644
index 0000000..f3d107a
--- /dev/null
+++ b/lifecycle/reactivestreams/api/2.1.0-alpha03.txt
@@ -0,0 +1,10 @@
+// Signature format: 3.0
+package androidx.lifecycle {
+
+  public final class LiveDataReactiveStreams {
+    method public static <T> androidx.lifecycle.LiveData<T> fromPublisher(org.reactivestreams.Publisher<T>);
+    method public static <T> org.reactivestreams.Publisher<T> toPublisher(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.LiveData<T>);
+  }
+
+}
+
diff --git a/lifecycle/reactivestreams/api/res-2.1.0-alpha03.txt b/lifecycle/reactivestreams/api/res-2.1.0-alpha03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lifecycle/reactivestreams/api/res-2.1.0-alpha03.txt
diff --git a/lifecycle/reactivestreams/ktx/api/2.1.0-alpha03.txt b/lifecycle/reactivestreams/ktx/api/2.1.0-alpha03.txt
new file mode 100644
index 0000000..659d07d
--- /dev/null
+++ b/lifecycle/reactivestreams/ktx/api/2.1.0-alpha03.txt
@@ -0,0 +1,11 @@
+// Signature format: 3.0
+package androidx.lifecycle {
+
+  public final class LiveDataReactiveSteamsKt {
+    ctor public LiveDataReactiveSteamsKt();
+    method public static inline <T> androidx.lifecycle.LiveData<T> toLiveData(org.reactivestreams.Publisher<T>);
+    method public static inline <T> org.reactivestreams.Publisher<T> toPublisher(androidx.lifecycle.LiveData<T>, androidx.lifecycle.LifecycleOwner lifecycle);
+  }
+
+}
+
diff --git a/lifecycle/reactivestreams/ktx/api/res-2.1.0-alpha03.txt b/lifecycle/reactivestreams/ktx/api/res-2.1.0-alpha03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lifecycle/reactivestreams/ktx/api/res-2.1.0-alpha03.txt
diff --git a/lifecycle/runtime/api/2.1.0-alpha03.txt b/lifecycle/runtime/api/2.1.0-alpha03.txt
new file mode 100644
index 0000000..0a652c0
--- /dev/null
+++ b/lifecycle/runtime/api/2.1.0-alpha03.txt
@@ -0,0 +1,20 @@
+// Signature format: 3.0
+package androidx.lifecycle {
+
+  public class LifecycleRegistry extends androidx.lifecycle.Lifecycle {
+    ctor public LifecycleRegistry(androidx.lifecycle.LifecycleOwner);
+    method public void addObserver(androidx.lifecycle.LifecycleObserver);
+    method public androidx.lifecycle.Lifecycle.State getCurrentState();
+    method public int getObserverCount();
+    method public void handleLifecycleEvent(androidx.lifecycle.Lifecycle.Event);
+    method @Deprecated @MainThread public void markState(androidx.lifecycle.Lifecycle.State);
+    method public void removeObserver(androidx.lifecycle.LifecycleObserver);
+    method @MainThread public void setCurrentState(androidx.lifecycle.Lifecycle.State);
+  }
+
+  @Deprecated public interface LifecycleRegistryOwner extends androidx.lifecycle.LifecycleOwner {
+    method @Deprecated public androidx.lifecycle.LifecycleRegistry getLifecycle();
+  }
+
+}
+
diff --git a/lifecycle/runtime/api/res-2.1.0-alpha03.txt b/lifecycle/runtime/api/res-2.1.0-alpha03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lifecycle/runtime/api/res-2.1.0-alpha03.txt
diff --git a/lifecycle/service/api/2.1.0-alpha03.txt b/lifecycle/service/api/2.1.0-alpha03.txt
new file mode 100644
index 0000000..a12d86e
--- /dev/null
+++ b/lifecycle/service/api/2.1.0-alpha03.txt
@@ -0,0 +1,21 @@
+// Signature format: 3.0
+package androidx.lifecycle {
+
+  public class LifecycleService extends android.app.Service implements androidx.lifecycle.LifecycleOwner {
+    ctor public LifecycleService();
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+    method @CallSuper public android.os.IBinder? onBind(android.content.Intent);
+    method @CallSuper public void onStart(android.content.Intent, int);
+  }
+
+  public class ServiceLifecycleDispatcher {
+    ctor public ServiceLifecycleDispatcher(androidx.lifecycle.LifecycleOwner);
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+    method public void onServicePreSuperOnBind();
+    method public void onServicePreSuperOnCreate();
+    method public void onServicePreSuperOnDestroy();
+    method public void onServicePreSuperOnStart();
+  }
+
+}
+
diff --git a/lifecycle/service/api/res-2.1.0-alpha03.txt b/lifecycle/service/api/res-2.1.0-alpha03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lifecycle/service/api/res-2.1.0-alpha03.txt
diff --git a/lifecycle/viewmodel/api/2.1.0-alpha03.txt b/lifecycle/viewmodel/api/2.1.0-alpha03.txt
new file mode 100644
index 0000000..0a6e010
--- /dev/null
+++ b/lifecycle/viewmodel/api/2.1.0-alpha03.txt
@@ -0,0 +1,51 @@
+// Signature format: 3.0
+package androidx.lifecycle {
+
+  public class AndroidViewModel extends androidx.lifecycle.ViewModel {
+    ctor public AndroidViewModel(android.app.Application);
+    method public <T extends android.app.Application> T getApplication();
+  }
+
+  public abstract class ViewModel {
+    ctor public ViewModel();
+    method protected void onCleared();
+  }
+
+  public class ViewModelProvider {
+    ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner, androidx.lifecycle.ViewModelProvider.Factory);
+    ctor public ViewModelProvider(androidx.lifecycle.ViewModelStore, androidx.lifecycle.ViewModelProvider.Factory);
+    ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner, androidx.lifecycle.ViewModelProvider.KeyedFactory);
+    ctor public ViewModelProvider(androidx.lifecycle.ViewModelStore, androidx.lifecycle.ViewModelProvider.KeyedFactory);
+    method @MainThread public <T extends androidx.lifecycle.ViewModel> T get(Class<T>);
+    method @MainThread public <T extends androidx.lifecycle.ViewModel> T get(String, Class<T>);
+  }
+
+  public static class ViewModelProvider.AndroidViewModelFactory extends androidx.lifecycle.ViewModelProvider.NewInstanceFactory {
+    ctor public ViewModelProvider.AndroidViewModelFactory(android.app.Application);
+    method public static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory getInstance(android.app.Application);
+  }
+
+  public static interface ViewModelProvider.Factory {
+    method public <T extends androidx.lifecycle.ViewModel> T create(Class<T>);
+  }
+
+  public static interface ViewModelProvider.KeyedFactory {
+    method public <T extends androidx.lifecycle.ViewModel> T create(String, Class<T>);
+  }
+
+  public static class ViewModelProvider.NewInstanceFactory implements androidx.lifecycle.ViewModelProvider.Factory {
+    ctor public ViewModelProvider.NewInstanceFactory();
+    method public <T extends androidx.lifecycle.ViewModel> T create(Class<T>);
+  }
+
+  public class ViewModelStore {
+    ctor public ViewModelStore();
+    method public final void clear();
+  }
+
+  public interface ViewModelStoreOwner {
+    method public androidx.lifecycle.ViewModelStore getViewModelStore();
+  }
+
+}
+
diff --git a/lifecycle/viewmodel/api/res-2.1.0-alpha03.txt b/lifecycle/viewmodel/api/res-2.1.0-alpha03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lifecycle/viewmodel/api/res-2.1.0-alpha03.txt
diff --git a/lifecycle/viewmodel/ktx/api/2.1.0-alpha03.txt b/lifecycle/viewmodel/ktx/api/2.1.0-alpha03.txt
new file mode 100644
index 0000000..2c78583
--- /dev/null
+++ b/lifecycle/viewmodel/ktx/api/2.1.0-alpha03.txt
@@ -0,0 +1,22 @@
+// Signature format: 3.0
+package androidx.lifecycle {
+
+  public final class ViewModelKt {
+    ctor public ViewModelKt();
+    method public static kotlinx.coroutines.CoroutineScope getViewModelScope(androidx.lifecycle.ViewModel);
+  }
+
+  public final class ViewModelLazy<VM extends androidx.lifecycle.ViewModel> implements kotlin.Lazy<VM> {
+    ctor public ViewModelLazy(kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStoreOwner> ownerProducer, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory> factoryProducer);
+    method public VM getValue();
+    method public boolean isInitialized();
+    property public VM value;
+  }
+
+  public final class ViewModelProviderKt {
+    ctor public ViewModelProviderKt();
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> VM! get(androidx.lifecycle.ViewModelProvider);
+  }
+
+}
+
diff --git a/lifecycle/viewmodel/ktx/api/res-2.1.0-alpha03.txt b/lifecycle/viewmodel/ktx/api/res-2.1.0-alpha03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lifecycle/viewmodel/ktx/api/res-2.1.0-alpha03.txt
diff --git a/loader/src/androidTest/java/androidx/loader/app/LoaderManagerTest.java b/loader/src/androidTest/java/androidx/loader/app/LoaderManagerTest.java
index da4a8ec1..8e7d67f 100644
--- a/loader/src/androidTest/java/androidx/loader/app/LoaderManagerTest.java
+++ b/loader/src/androidTest/java/androidx/loader/app/LoaderManagerTest.java
@@ -204,6 +204,38 @@
                 initialCallback.mLoader.isReset());
     }
 
+    /**
+     * Ensures that calling restartLoader from onLoadFinished will not reset current loader.
+     * This is especially important for CursorLoader which closes cursor when Loader is reset.
+     * This means that rest of onLoadFinished could access closed cursor.
+     */
+    @Test
+    public void testRestartLoaderWhileDeliveringData() throws Throwable {
+        CountDownLatch initialCountDownLatch = new CountDownLatch(1);
+        final DelayLoaderCallbacks initialCallback = new DelayLoaderCallbacks(mock(Context.class),
+                initialCountDownLatch) {
+            @Override
+            public void onLoadFinished(@NonNull Loader<Boolean> loader, Boolean data) {
+                super.onLoadFinished(loader, data);
+                assertFalse("Assumption is that loader is not reset in onLoadFinished",
+                        loader.isReset());
+                mLoaderManager.restartLoader(45, null,
+                        new DelayLoaderCallbacks(mock(Context.class), new CountDownLatch(1)));
+                assertFalse("Loader should not be reset when restarted in onLoadFinished",
+                        loader.isReset());
+            }
+        };
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mLoaderManager.initLoader(45, null, initialCallback);
+            }
+        });
+        // Wait for the Loader to return data
+        initialCountDownLatch.await(1, TimeUnit.SECONDS);
+    }
+
+
     @Test
     public void testRestartLoaderMultiple() throws Throwable {
         CountDownLatch initialCountDownLatch = new CountDownLatch(1);
diff --git a/loader/src/main/java/androidx/loader/app/LoaderManagerImpl.java b/loader/src/main/java/androidx/loader/app/LoaderManagerImpl.java
index 37586b2..00dceb2 100644
--- a/loader/src/main/java/androidx/loader/app/LoaderManagerImpl.java
+++ b/loader/src/main/java/androidx/loader/app/LoaderManagerImpl.java
@@ -250,8 +250,8 @@
                 Log.v(TAG, "  onLoadFinished in " + mLoader + ": "
                         + mLoader.dataToString(data));
             }
-            mCallback.onLoadFinished(mLoader, data);
             mDeliveredData = true;
+            mCallback.onLoadFinished(mLoader, data);
         }
 
         boolean hasDeliveredData() {
diff --git a/media2-widget/src/main/java/androidx/media2/widget/MediaControlView.java b/media2-widget/src/main/java/androidx/media2/widget/MediaControlView.java
index bfa3dde..bd993d9 100644
--- a/media2-widget/src/main/java/androidx/media2/widget/MediaControlView.java
+++ b/media2-widget/src/main/java/androidx/media2/widget/MediaControlView.java
@@ -151,7 +151,8 @@
     // Int for defining the UX state where the views are being animated (shown or hidden).
     private static final int UX_STATE_ANIMATING = 3;
 
-    private static final long DEFAULT_SHOW_CONTROLLER_INTERVAL_MS = 2000;
+    private static final long DISABLE_DELAYED_ANIMATION = -1;
+    private static final long DEFAULT_DELAYED_ANIMATION_INTERVAL_MS = 2000;
     private static final long DEFAULT_PROGRESS_UPDATE_TIME_MS = 1000;
     private static final long REWIND_TIME_MS = 10000;
     private static final long FORWARD_TIME_MS = 30000;
@@ -183,7 +184,7 @@
     int mSizeType = SIZE_TYPE_UNDEFINED;
     int mUxState;
     long mDuration;
-    long mShowControllerIntervalMs;
+    long mDelayedAnimationIntervalMs;
     long mCurrentSeekPosition;
     long mNextSeekPosition;
     boolean mDragging;
@@ -275,7 +276,7 @@
         mController = new Controller();
         inflate(context, R.layout.media_controller, this);
         initControllerView();
-        mShowControllerIntervalMs = DEFAULT_SHOW_CONTROLLER_INTERVAL_MS;
+        mDelayedAnimationIntervalMs = DEFAULT_DELAYED_ANIMATION_INTERVAL_MS;
         mAccessibilityManager = (AccessibilityManager) context.getSystemService(
                 Context.ACCESSIBILITY_SERVICE);
     }
@@ -331,7 +332,11 @@
     public boolean onTouchEvent(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_UP) {
             if (mMediaType != MEDIA_TYPE_MUSIC || mSizeType != SIZE_TYPE_FULL) {
-                toggleMediaControlViewVisibility();
+                if (mUxState == UX_STATE_ALL_VISIBLE) {
+                    hideMediaControlView();
+                } else {
+                    showMediaControlView();
+                }
             }
         }
         return true;
@@ -341,7 +346,11 @@
     public boolean onTrackballEvent(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_UP) {
             if (mMediaType != MEDIA_TYPE_MUSIC || mSizeType != SIZE_TYPE_FULL) {
-                toggleMediaControlViewVisibility();
+                if (mUxState == UX_STATE_ALL_VISIBLE) {
+                    hideMediaControlView();
+                } else {
+                    showMediaControlView();
+                }
             }
         }
         return true;
@@ -526,8 +535,8 @@
         }
     }
 
-    void setShowControllerInterval(long interval) {
-        mShowControllerIntervalMs = interval;
+    void setDelayedAnimationInterval(long interval) {
+        mDelayedAnimationIntervalMs = interval;
     }
 
     ///////////////////////////////////////////////////
@@ -808,7 +817,7 @@
             boolean isShowing = getVisibility() == View.VISIBLE;
             if (!mDragging && isShowing && mController.isPlaying()) {
                 long pos = setProgress();
-                postDelayed(mUpdateProgress,
+                postDelayedRunnable(mUpdateProgress,
                         DEFAULT_PROGRESS_UPDATE_TIME_MS - (pos % DEFAULT_PROGRESS_UPDATE_TIME_MS));
             }
         }
@@ -909,33 +918,36 @@
         }
     }
 
-    private void toggleMediaControlViewVisibility() {
-        if (shouldNotHideBars() || mShowControllerIntervalMs == 0
-                || mUxState == UX_STATE_ANIMATING) {
+    private void showMediaControlView() {
+        if (mUxState == UX_STATE_ANIMATING) {
             return;
         }
         removeCallbacks(mHideMainBars);
         removeCallbacks(mHideProgressBar);
 
-        switch (mUxState) {
-            case UX_STATE_NONE_VISIBLE:
-                post(mShowAllBars);
-                break;
-            case UX_STATE_ONLY_PROGRESS_VISIBLE:
-                post(mShowMainBars);
-                break;
-            case UX_STATE_ALL_VISIBLE:
-                post(mHideAllBars);
-                break;
+        if (mUxState == UX_STATE_NONE_VISIBLE) {
+            post(mShowAllBars);
+        } else if (mUxState == UX_STATE_ONLY_PROGRESS_VISIBLE) {
+            post(mShowMainBars);
         }
     }
 
+    private void hideMediaControlView() {
+        if (shouldNotHideBars() || mUxState == UX_STATE_ANIMATING) {
+            return;
+        }
+        removeCallbacks(mHideMainBars);
+        removeCallbacks(mHideProgressBar);
+
+        post(mHideAllBars);
+    }
+
     private final Runnable mShowAllBars = new Runnable() {
         @Override
         public void run() {
             mShowAllBarsAnimator.start();
             if (mController.isPlaying()) {
-                postDelayed(mHideMainBars, mShowControllerIntervalMs);
+                postDelayedRunnable(mHideMainBars, mDelayedAnimationIntervalMs);
             }
         }
     };
@@ -944,7 +956,7 @@
         @Override
         public void run() {
             mShowMainBarsAnimator.start();
-            postDelayed(mHideMainBars, mShowControllerIntervalMs);
+            postDelayedRunnable(mHideMainBars, mDelayedAnimationIntervalMs);
         }
     };
 
@@ -965,7 +977,7 @@
                 return;
             }
             mHideMainBarsAnimator.start();
-            postDelayed(mHideProgressBar, mShowControllerIntervalMs);
+            postDelayedRunnable(mHideProgressBar, mDelayedAnimationIntervalMs);
         }
     };
 
@@ -1256,7 +1268,7 @@
                 @Override
                 public void onDismiss() {
                     if (mNeedToHideBars) {
-                        postDelayed(mHideMainBars, mShowControllerIntervalMs);
+                        postDelayedRunnable(mHideMainBars, mDelayedAnimationIntervalMs);
                     }
                 }
             };
@@ -1476,7 +1488,7 @@
     void resetHideCallbacks() {
         removeCallbacks(mHideMainBars);
         removeCallbacks(mHideProgressBar);
-        postDelayed(mHideMainBars, mShowControllerIntervalMs);
+        postDelayedRunnable(mHideMainBars, mDelayedAnimationIntervalMs);
     }
 
     void updateAllowedCommands(SessionCommandGroup commands) {
@@ -1638,6 +1650,12 @@
         }
     }
 
+    void postDelayedRunnable(Runnable runnable, long interval) {
+        if (interval != DISABLE_DELAYED_ANIMATION) {
+            postDelayed(runnable, interval);
+        }
+    }
+
     private class SettingsAdapter extends BaseAdapter {
         private List<Integer> mIconIds;
         private List<String> mMainTexts;
@@ -2049,7 +2067,7 @@
                     removeCallbacks(mUpdateProgress);
                     removeCallbacks(mHideMainBars);
                     post(mUpdateProgress);
-                    postDelayed(mHideMainBars, mShowControllerIntervalMs);
+                    postDelayedRunnable(mHideMainBars, mDelayedAnimationIntervalMs);
                 }
             }
 
diff --git a/media2-widget/src/main/java/androidx/media2/widget/VideoView.java b/media2-widget/src/main/java/androidx/media2/widget/VideoView.java
index 0171194..1af94f4 100644
--- a/media2-widget/src/main/java/androidx/media2/widget/VideoView.java
+++ b/media2-widget/src/main/java/androidx/media2/widget/VideoView.java
@@ -405,7 +405,7 @@
      */
     public void setMediaControlView(@NonNull MediaControlView mediaControlView, long intervalMs) {
         mMediaControlView = mediaControlView;
-        mMediaControlView.setShowControllerInterval(intervalMs);
+        mMediaControlView.setDelayedAnimationInterval(intervalMs);
 
         if (isAttachedToWindow()) {
             attachMediaControlView();
@@ -804,10 +804,8 @@
                 // Save file name as title since the file may not have a title Metadata.
                 if (UriUtil.isFromNetwork(uri)) {
                     path = uri.getPath();
-                } else if ("file".equals(uri.getScheme())) {
-                    path = uri.getLastPathSegment();
                 } else {
-                    // TODO: needs default title. b/120515913
+                    path = uri.getLastPathSegment();
                 }
                 retriever = new MediaMetadataRetriever();
                 retriever.setDataSource(getContext(), uri);
diff --git a/navigation/common/api/1.0.0-beta02.txt b/navigation/common/api/1.0.0-beta02.txt
new file mode 100644
index 0000000..6dd3420
--- /dev/null
+++ b/navigation/common/api/1.0.0-beta02.txt
@@ -0,0 +1,192 @@
+// Signature format: 3.0
+package androidx.navigation {
+
+  public final class ActionOnlyNavDirections implements androidx.navigation.NavDirections {
+    ctor public ActionOnlyNavDirections(int);
+    method public int getActionId();
+    method public android.os.Bundle getArguments();
+  }
+
+  public final class NavAction {
+    ctor public NavAction(@IdRes int);
+    ctor public NavAction(@IdRes int, androidx.navigation.NavOptions?);
+    ctor public NavAction(@IdRes int, androidx.navigation.NavOptions?, android.os.Bundle?);
+    method public android.os.Bundle? getDefaultArguments();
+    method public int getDestinationId();
+    method public androidx.navigation.NavOptions? getNavOptions();
+    method public void setDefaultArguments(android.os.Bundle?);
+    method public void setNavOptions(androidx.navigation.NavOptions?);
+  }
+
+  public interface NavArgs {
+  }
+
+  public final class NavArgument {
+    method public Object? getDefaultValue();
+    method public androidx.navigation.NavType<?> getType();
+    method public boolean isDefaultValuePresent();
+    method public boolean isNullable();
+  }
+
+  public static final class NavArgument.Builder {
+    ctor public NavArgument.Builder();
+    method public androidx.navigation.NavArgument build();
+    method public androidx.navigation.NavArgument.Builder setDefaultValue(Object?);
+    method public androidx.navigation.NavArgument.Builder setIsNullable(boolean);
+    method public androidx.navigation.NavArgument.Builder setType(androidx.navigation.NavType<?>);
+  }
+
+  public class NavDestination {
+    ctor public NavDestination(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>);
+    ctor public NavDestination(String);
+    method public final void addArgument(String, androidx.navigation.NavArgument);
+    method public final void addDeepLink(String);
+    method public final androidx.navigation.NavAction? getAction(@IdRes int);
+    method public final java.util.Map<java.lang.String,androidx.navigation.NavArgument> getArguments();
+    method @IdRes public final int getId();
+    method public final CharSequence? getLabel();
+    method public final String getNavigatorName();
+    method public final androidx.navigation.NavGraph? getParent();
+    method @CallSuper public void onInflate(android.content.Context, android.util.AttributeSet);
+    method protected static <C> Class<? extends C> parseClassFromName(android.content.Context, String, Class<? extends C>);
+    method public final void putAction(@IdRes int, @IdRes int);
+    method public final void putAction(@IdRes int, androidx.navigation.NavAction);
+    method public final void removeAction(@IdRes int);
+    method public final void removeArgument(String);
+    method public final void setId(@IdRes int);
+    method public final void setLabel(CharSequence?);
+  }
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface NavDestination.ClassType {
+    method public abstract Class value();
+  }
+
+  public interface NavDirections {
+    method @IdRes public int getActionId();
+    method public android.os.Bundle getArguments();
+  }
+
+  public class NavGraph extends androidx.navigation.NavDestination implements java.lang.Iterable<androidx.navigation.NavDestination> {
+    ctor public NavGraph(androidx.navigation.Navigator<? extends androidx.navigation.NavGraph>);
+    method public final void addAll(androidx.navigation.NavGraph);
+    method public final void addDestination(androidx.navigation.NavDestination);
+    method public final void addDestinations(java.util.Collection<androidx.navigation.NavDestination>);
+    method public final void addDestinations(androidx.navigation.NavDestination...);
+    method public final void clear();
+    method public final androidx.navigation.NavDestination? findNode(@IdRes int);
+    method @IdRes public final int getStartDestination();
+    method public final java.util.Iterator<androidx.navigation.NavDestination> iterator();
+    method public final void remove(androidx.navigation.NavDestination);
+    method public final void setStartDestination(@IdRes int);
+  }
+
+  @androidx.navigation.Navigator.Name("navigation") public class NavGraphNavigator extends androidx.navigation.Navigator<androidx.navigation.NavGraph> {
+    ctor public NavGraphNavigator(androidx.navigation.NavigatorProvider);
+    method public androidx.navigation.NavGraph createDestination();
+    method public androidx.navigation.NavDestination? navigate(androidx.navigation.NavGraph, android.os.Bundle?, androidx.navigation.NavOptions?, androidx.navigation.Navigator.Extras?);
+    method public boolean popBackStack();
+  }
+
+  public final class NavOptions {
+    method @AnimRes @AnimatorRes public int getEnterAnim();
+    method @AnimRes @AnimatorRes public int getExitAnim();
+    method @AnimRes @AnimatorRes public int getPopEnterAnim();
+    method @AnimRes @AnimatorRes public int getPopExitAnim();
+    method @IdRes public int getPopUpTo();
+    method public boolean isPopUpToInclusive();
+    method public boolean shouldLaunchSingleTop();
+  }
+
+  public static final class NavOptions.Builder {
+    ctor public NavOptions.Builder();
+    method public androidx.navigation.NavOptions build();
+    method public androidx.navigation.NavOptions.Builder setEnterAnim(@AnimRes @AnimatorRes int);
+    method public androidx.navigation.NavOptions.Builder setExitAnim(@AnimRes @AnimatorRes int);
+    method public androidx.navigation.NavOptions.Builder setLaunchSingleTop(boolean);
+    method public androidx.navigation.NavOptions.Builder setPopEnterAnim(@AnimRes @AnimatorRes int);
+    method public androidx.navigation.NavOptions.Builder setPopExitAnim(@AnimRes @AnimatorRes int);
+    method public androidx.navigation.NavOptions.Builder setPopUpTo(@IdRes int, boolean);
+  }
+
+  public abstract class NavType<T> {
+    method public static androidx.navigation.NavType<?> fromArgType(String?, String?);
+    method public abstract T? get(android.os.Bundle, String);
+    method public abstract String getName();
+    method public boolean isNullableAllowed();
+    method public abstract T parseValue(String);
+    method public abstract void put(android.os.Bundle, String, T?);
+    field public static final androidx.navigation.NavType<boolean[]> BoolArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Boolean> BoolType;
+    field public static final androidx.navigation.NavType<float[]> FloatArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Float> FloatType;
+    field public static final androidx.navigation.NavType<int[]> IntArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Integer> IntType;
+    field public static final androidx.navigation.NavType<long[]> LongArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Long> LongType;
+    field public static final androidx.navigation.NavType<java.lang.Integer> ReferenceType;
+    field public static final androidx.navigation.NavType<java.lang.String[]> StringArrayType;
+    field public static final androidx.navigation.NavType<java.lang.String> StringType;
+  }
+
+  public static final class NavType.EnumType<D extends java.lang.Enum> extends androidx.navigation.NavType.SerializableType<D> {
+    ctor public NavType.EnumType(Class<D>);
+  }
+
+  public static final class NavType.ParcelableArrayType<D extends android.os.Parcelable> extends androidx.navigation.NavType<D[]> {
+    ctor public NavType.ParcelableArrayType(Class<D>);
+    method public D[]? get(android.os.Bundle, String);
+    method public String getName();
+    method public D[] parseValue(String);
+    method public void put(android.os.Bundle, String, D[]?);
+  }
+
+  public static final class NavType.ParcelableType<D> extends androidx.navigation.NavType<D> {
+    ctor public NavType.ParcelableType(Class<D>);
+    method public D? get(android.os.Bundle, String);
+    method public String getName();
+    method public D parseValue(String);
+    method public void put(android.os.Bundle, String, D?);
+  }
+
+  public static final class NavType.SerializableArrayType<D extends java.io.Serializable> extends androidx.navigation.NavType<D[]> {
+    ctor public NavType.SerializableArrayType(Class<D>);
+    method public D[]? get(android.os.Bundle, String);
+    method public String getName();
+    method public D[] parseValue(String);
+    method public void put(android.os.Bundle, String, D[]?);
+  }
+
+  public static class NavType.SerializableType<D extends java.io.Serializable> extends androidx.navigation.NavType<D> {
+    ctor public NavType.SerializableType(Class<D>);
+    method public D? get(android.os.Bundle, String);
+    method public String getName();
+    method public D parseValue(String);
+    method public void put(android.os.Bundle, String, D?);
+  }
+
+  public abstract class Navigator<D extends androidx.navigation.NavDestination> {
+    ctor public Navigator();
+    method public abstract D createDestination();
+    method public abstract androidx.navigation.NavDestination? navigate(D, android.os.Bundle?, androidx.navigation.NavOptions?, androidx.navigation.Navigator.Extras?);
+    method public void onRestoreState(android.os.Bundle);
+    method public android.os.Bundle? onSaveState();
+    method public abstract boolean popBackStack();
+  }
+
+  public static interface Navigator.Extras {
+  }
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface Navigator.Name {
+    method public abstract String value();
+  }
+
+  public class NavigatorProvider {
+    ctor public NavigatorProvider();
+    method public final androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? addNavigator(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>);
+    method @CallSuper public androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? addNavigator(String, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>);
+    method public final <T extends androidx.navigation.Navigator<?>> T getNavigator(Class<T>);
+    method @CallSuper public <T extends androidx.navigation.Navigator<?>> T getNavigator(String);
+  }
+
+}
+
diff --git a/navigation/common/api/res-1.0.0-beta02.txt b/navigation/common/api/res-1.0.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/common/api/res-1.0.0-beta02.txt
diff --git a/navigation/common/ktx/api/1.0.0-beta02.txt b/navigation/common/ktx/api/1.0.0-beta02.txt
new file mode 100644
index 0000000..6da57db
--- /dev/null
+++ b/navigation/common/ktx/api/1.0.0-beta02.txt
@@ -0,0 +1,129 @@
+// Signature format: 3.0
+package androidx.navigation {
+
+  @androidx.navigation.NavOptionsDsl public final class AnimBuilder {
+    ctor public AnimBuilder();
+    method public int getEnter();
+    method public int getExit();
+    method public int getPopEnter();
+    method public int getPopExit();
+    method public void setEnter(int p);
+    method public void setExit(int p);
+    method public void setPopEnter(int p);
+    method public void setPopExit(int p);
+    property public final int enter;
+    property public final int exit;
+    property public final int popEnter;
+    property public final int popExit;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class NavActionBuilder {
+    ctor public NavActionBuilder();
+    method public int getDestinationId();
+    method public void navOptions(kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> optionsBuilder);
+    method public void setDestinationId(int p);
+    property public final int destinationId;
+  }
+
+  public final class NavArgsLazy<Args extends androidx.navigation.NavArgs> implements kotlin.Lazy<Args> {
+    ctor public NavArgsLazy(kotlin.reflect.KClass<Args> navArgsClass, kotlin.jvm.functions.Function0<android.os.Bundle> argumentProducer);
+    method public Args getValue();
+    method public boolean isInitialized();
+    property public Args value;
+  }
+
+  public final class NavArgsLazyKt {
+    ctor public NavArgsLazyKt();
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class NavArgumentBuilder {
+    ctor public NavArgumentBuilder();
+    method public androidx.navigation.NavArgument build();
+    method public Object? getDefaultValue();
+    method public boolean getNullable();
+    method public androidx.navigation.NavType<?> getType();
+    method public void setDefaultValue(Object? value);
+    method public void setNullable(boolean value);
+    method public void setType(androidx.navigation.NavType<?> value);
+    property public final Object? defaultValue;
+    property public final boolean nullable;
+    property public final androidx.navigation.NavType<?> type;
+  }
+
+  @androidx.navigation.NavDestinationDsl public class NavDestinationBuilder<D extends androidx.navigation.NavDestination> {
+    ctor public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, @IdRes int id);
+    method public final void action(int actionId, kotlin.jvm.functions.Function1<? super androidx.navigation.NavActionBuilder,kotlin.Unit> actionBuilder);
+    method public final void argument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> argumentBuilder);
+    method public D build();
+    method public final void deepLink(String uriPattern);
+    method public final int getId();
+    method public final CharSequence? getLabel();
+    method protected final androidx.navigation.Navigator<? extends D> getNavigator();
+    method public final void setLabel(CharSequence? p);
+    property public final CharSequence? label;
+  }
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public @interface NavDestinationDsl {
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class NavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.NavGraph> {
+    ctor public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+    method public void addDestination(androidx.navigation.NavDestination destination);
+    method public androidx.navigation.NavGraph build();
+    method public <D extends androidx.navigation.NavDestination> void destination(androidx.navigation.NavDestinationBuilder<? extends D> navDestination);
+    method public androidx.navigation.NavigatorProvider getProvider();
+    method public operator void unaryPlus(androidx.navigation.NavDestination);
+  }
+
+  public final class NavGraphBuilderKt {
+    ctor public NavGraphBuilderKt();
+    method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, @IdRes int id = 0, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method public static inline void navigation(androidx.navigation.NavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavGraphKt {
+    ctor public NavGraphKt();
+    method public static operator boolean contains(androidx.navigation.NavGraph, @IdRes int id);
+    method public static inline operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, @IdRes int id);
+    method public static inline operator void minusAssign(androidx.navigation.NavGraph, androidx.navigation.NavDestination node);
+    method public static inline operator void plusAssign(androidx.navigation.NavGraph, androidx.navigation.NavDestination node);
+    method public static inline operator void plusAssign(androidx.navigation.NavGraph, androidx.navigation.NavGraph other);
+  }
+
+  @androidx.navigation.NavOptionsDsl public final class NavOptionsBuilder {
+    ctor public NavOptionsBuilder();
+    method public void anim(kotlin.jvm.functions.Function1<? super androidx.navigation.AnimBuilder,kotlin.Unit> animBuilder);
+    method public boolean getLaunchSingleTop();
+    method public int getPopUpTo();
+    method public void popUpTo(@IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.PopUpToBuilder,kotlin.Unit> popUpToBuilder);
+    method public void setLaunchSingleTop(boolean p);
+    method public void setPopUpTo(int value);
+    property public final boolean launchSingleTop;
+    property public final int popUpTo;
+  }
+
+  public final class NavOptionsBuilderKt {
+    ctor public NavOptionsBuilderKt();
+    method public static androidx.navigation.NavOptions navOptions(kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> optionsBuilder);
+  }
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public @interface NavOptionsDsl {
+  }
+
+  public final class NavigatorProviderKt {
+    ctor public NavigatorProviderKt();
+    method public static inline operator <T extends androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>> T get(androidx.navigation.NavigatorProvider, String name);
+    method public static inline operator <T extends androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>> T get(androidx.navigation.NavigatorProvider, kotlin.reflect.KClass<T> clazz);
+    method public static inline operator void plusAssign(androidx.navigation.NavigatorProvider, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+    method public static inline operator androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? set(androidx.navigation.NavigatorProvider, String name, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+  }
+
+  @androidx.navigation.NavOptionsDsl public final class PopUpToBuilder {
+    ctor public PopUpToBuilder();
+    method public boolean getInclusive();
+    method public void setInclusive(boolean p);
+    property public final boolean inclusive;
+  }
+
+}
+
diff --git a/navigation/common/ktx/api/res-1.0.0-beta02.txt b/navigation/common/ktx/api/res-1.0.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/common/ktx/api/res-1.0.0-beta02.txt
diff --git a/navigation/fragment/api/1.0.0-beta02.txt b/navigation/fragment/api/1.0.0-beta02.txt
new file mode 100644
index 0000000..8759a64
--- /dev/null
+++ b/navigation/fragment/api/1.0.0-beta02.txt
@@ -0,0 +1,40 @@
+// Signature format: 3.0
+package androidx.navigation.fragment {
+
+  @androidx.navigation.Navigator.Name("fragment") public class FragmentNavigator extends androidx.navigation.Navigator<androidx.navigation.fragment.FragmentNavigator.Destination> {
+    ctor public FragmentNavigator(android.content.Context, android.support.v4.app.FragmentManager, int);
+    method public androidx.navigation.fragment.FragmentNavigator.Destination createDestination();
+    method public android.support.v4.app.Fragment instantiateFragment(android.content.Context, android.support.v4.app.FragmentManager, String, android.os.Bundle?);
+    method public androidx.navigation.NavDestination? navigate(androidx.navigation.fragment.FragmentNavigator.Destination, android.os.Bundle?, androidx.navigation.NavOptions?, androidx.navigation.Navigator.Extras?);
+    method public boolean popBackStack();
+  }
+
+  @androidx.navigation.NavDestination.ClassType(Fragment.class) public static class FragmentNavigator.Destination extends androidx.navigation.NavDestination {
+    ctor public FragmentNavigator.Destination(androidx.navigation.NavigatorProvider);
+    ctor public FragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination>);
+    method public final String getClassName();
+    method public final androidx.navigation.fragment.FragmentNavigator.Destination setClassName(String);
+  }
+
+  public static final class FragmentNavigator.Extras implements androidx.navigation.Navigator.Extras {
+    method public java.util.Map<android.view.View,java.lang.String> getSharedElements();
+  }
+
+  public static final class FragmentNavigator.Extras.Builder {
+    ctor public FragmentNavigator.Extras.Builder();
+    method public androidx.navigation.fragment.FragmentNavigator.Extras.Builder addSharedElement(android.view.View, String);
+    method public androidx.navigation.fragment.FragmentNavigator.Extras.Builder addSharedElements(java.util.Map<android.view.View,java.lang.String>);
+    method public androidx.navigation.fragment.FragmentNavigator.Extras build();
+  }
+
+  public class NavHostFragment extends android.support.v4.app.Fragment implements androidx.navigation.NavHost {
+    ctor public NavHostFragment();
+    method public static androidx.navigation.fragment.NavHostFragment create(@NavigationRes int);
+    method public static androidx.navigation.fragment.NavHostFragment create(@NavigationRes int, android.os.Bundle?);
+    method protected androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> createFragmentNavigator();
+    method public static androidx.navigation.NavController findNavController(android.support.v4.app.Fragment);
+    method public final androidx.navigation.NavController getNavController();
+  }
+
+}
+
diff --git a/navigation/fragment/api/res-1.0.0-beta02.txt b/navigation/fragment/api/res-1.0.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/fragment/api/res-1.0.0-beta02.txt
diff --git a/navigation/fragment/ktx/api/1.0.0-beta02.txt b/navigation/fragment/ktx/api/1.0.0-beta02.txt
new file mode 100644
index 0000000..0e75320
--- /dev/null
+++ b/navigation/fragment/ktx/api/1.0.0-beta02.txt
@@ -0,0 +1,31 @@
+// Signature format: 3.0
+package androidx.navigation.fragment {
+
+  public final class FragmentKt {
+    ctor public FragmentKt();
+    method public static androidx.navigation.NavController findNavController(android.support.v4.app.Fragment);
+  }
+
+  public final class FragmentNavArgsLazyKt {
+    ctor public FragmentNavArgsLazyKt();
+    method @MainThread public static inline <reified Args extends androidx.navigation.NavArgs> androidx.navigation.NavArgsLazy<Args>! navArgs(android.support.v4.app.Fragment);
+  }
+
+  public final class FragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
+    ctor public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends android.support.v4.app.Fragment> fragmentClass);
+    method public androidx.navigation.fragment.FragmentNavigator.Destination build();
+  }
+
+  public final class FragmentNavigatorDestinationBuilderKt {
+    ctor public FragmentNavigatorDestinationBuilderKt();
+    method public static inline <reified F extends android.support.v4.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, @IdRes int id);
+    method public static inline <reified F extends android.support.v4.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.FragmentNavigatorDestinationBuilder,kotlin.Unit>! builder);
+  }
+
+  public final class FragmentNavigatorExtrasKt {
+    ctor public FragmentNavigatorExtrasKt();
+    method public static androidx.navigation.fragment.FragmentNavigator.Extras FragmentNavigatorExtras(kotlin.Pair<? extends android.view.View,java.lang.String>... sharedElements);
+  }
+
+}
+
diff --git a/navigation/fragment/ktx/api/res-1.0.0-beta02.txt b/navigation/fragment/ktx/api/res-1.0.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/fragment/ktx/api/res-1.0.0-beta02.txt
diff --git a/navigation/runtime/api/1.0.0-beta02.txt b/navigation/runtime/api/1.0.0-beta02.txt
new file mode 100644
index 0000000..0073e0d
--- /dev/null
+++ b/navigation/runtime/api/1.0.0-beta02.txt
@@ -0,0 +1,102 @@
+// Signature format: 3.0
+package androidx.navigation {
+
+  @androidx.navigation.Navigator.Name("activity") public class ActivityNavigator extends androidx.navigation.Navigator<androidx.navigation.ActivityNavigator.Destination> {
+    ctor public ActivityNavigator(android.content.Context);
+    method public static void applyPopAnimationsToPendingTransition(android.app.Activity);
+    method public androidx.navigation.ActivityNavigator.Destination createDestination();
+    method public androidx.navigation.NavDestination? navigate(androidx.navigation.ActivityNavigator.Destination, android.os.Bundle?, androidx.navigation.NavOptions?, androidx.navigation.Navigator.Extras?);
+    method public boolean popBackStack();
+  }
+
+  @androidx.navigation.NavDestination.ClassType(Activity.class) public static class ActivityNavigator.Destination extends androidx.navigation.NavDestination {
+    ctor public ActivityNavigator.Destination(androidx.navigation.NavigatorProvider);
+    ctor public ActivityNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.ActivityNavigator.Destination>);
+    method public final String? getAction();
+    method public final android.content.ComponentName? getComponent();
+    method public final android.net.Uri? getData();
+    method public final String? getDataPattern();
+    method public final android.content.Intent? getIntent();
+    method public final androidx.navigation.ActivityNavigator.Destination setAction(String?);
+    method public final androidx.navigation.ActivityNavigator.Destination setComponentName(android.content.ComponentName?);
+    method public final androidx.navigation.ActivityNavigator.Destination setData(android.net.Uri?);
+    method public final androidx.navigation.ActivityNavigator.Destination setDataPattern(String?);
+    method public final androidx.navigation.ActivityNavigator.Destination setIntent(android.content.Intent?);
+  }
+
+  public static final class ActivityNavigator.Extras implements androidx.navigation.Navigator.Extras {
+    method public android.support.v4.app.ActivityOptionsCompat? getActivityOptions();
+    method public int getFlags();
+  }
+
+  public static final class ActivityNavigator.Extras.Builder {
+    ctor public ActivityNavigator.Extras.Builder();
+    method public androidx.navigation.ActivityNavigator.Extras.Builder addFlags(int);
+    method public androidx.navigation.ActivityNavigator.Extras build();
+    method public androidx.navigation.ActivityNavigator.Extras.Builder setActivityOptions(android.support.v4.app.ActivityOptionsCompat);
+  }
+
+  public class NavController {
+    ctor public NavController(android.content.Context);
+    method public void addOnDestinationChangedListener(androidx.navigation.NavController.OnDestinationChangedListener);
+    method public androidx.navigation.NavDeepLinkBuilder createDeepLink();
+    method public androidx.navigation.NavDestination? getCurrentDestination();
+    method public androidx.navigation.NavGraph getGraph();
+    method public androidx.navigation.NavInflater getNavInflater();
+    method public androidx.navigation.NavigatorProvider getNavigatorProvider();
+    method public boolean handleDeepLink(android.content.Intent?);
+    method public void navigate(@IdRes int);
+    method public void navigate(@IdRes int, android.os.Bundle?);
+    method public void navigate(@IdRes int, android.os.Bundle?, androidx.navigation.NavOptions?);
+    method public void navigate(@IdRes int, android.os.Bundle?, androidx.navigation.NavOptions?, androidx.navigation.Navigator.Extras?);
+    method public void navigate(androidx.navigation.NavDirections);
+    method public void navigate(androidx.navigation.NavDirections, androidx.navigation.NavOptions?);
+    method public void navigate(androidx.navigation.NavDirections, androidx.navigation.Navigator.Extras);
+    method public boolean navigateUp();
+    method public boolean popBackStack();
+    method public boolean popBackStack(@IdRes int, boolean);
+    method public void removeOnDestinationChangedListener(androidx.navigation.NavController.OnDestinationChangedListener);
+    method @CallSuper public void restoreState(android.os.Bundle?);
+    method @CallSuper public android.os.Bundle? saveState();
+    method @CallSuper public void setGraph(@NavigationRes int);
+    method @CallSuper public void setGraph(@NavigationRes int, android.os.Bundle?);
+    method @CallSuper public void setGraph(androidx.navigation.NavGraph);
+    method @CallSuper public void setGraph(androidx.navigation.NavGraph, android.os.Bundle?);
+    field public static final String KEY_DEEP_LINK_INTENT = "android-support-nav:controller:deepLinkIntent";
+  }
+
+  public static interface NavController.OnDestinationChangedListener {
+    method public void onDestinationChanged(androidx.navigation.NavController, androidx.navigation.NavDestination, android.os.Bundle?);
+  }
+
+  public final class NavDeepLinkBuilder {
+    ctor public NavDeepLinkBuilder(android.content.Context);
+    method public android.app.PendingIntent createPendingIntent();
+    method public android.support.v4.app.TaskStackBuilder createTaskStackBuilder();
+    method public androidx.navigation.NavDeepLinkBuilder setArguments(android.os.Bundle?);
+    method public androidx.navigation.NavDeepLinkBuilder setComponentName(Class<? extends android.app.Activity>);
+    method public androidx.navigation.NavDeepLinkBuilder setComponentName(android.content.ComponentName);
+    method public androidx.navigation.NavDeepLinkBuilder setDestination(@IdRes int);
+    method public androidx.navigation.NavDeepLinkBuilder setGraph(@NavigationRes int);
+    method public androidx.navigation.NavDeepLinkBuilder setGraph(androidx.navigation.NavGraph);
+  }
+
+  public interface NavHost {
+    method public androidx.navigation.NavController getNavController();
+  }
+
+  public final class NavInflater {
+    ctor public NavInflater(android.content.Context, androidx.navigation.NavigatorProvider);
+    method public androidx.navigation.NavGraph inflate(@NavigationRes int);
+  }
+
+  public final class Navigation {
+    method public static android.view.View.OnClickListener createNavigateOnClickListener(@IdRes int);
+    method public static android.view.View.OnClickListener createNavigateOnClickListener(@IdRes int, android.os.Bundle?);
+    method public static androidx.navigation.NavController findNavController(android.app.Activity, @IdRes int);
+    method public static androidx.navigation.NavController findNavController(android.view.View);
+    method public static void setViewNavController(android.view.View, androidx.navigation.NavController?);
+  }
+
+}
+
diff --git a/navigation/runtime/api/res-1.0.0-beta02.txt b/navigation/runtime/api/res-1.0.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/runtime/api/res-1.0.0-beta02.txt
diff --git a/navigation/runtime/ktx/api/1.0.0-beta02.txt b/navigation/runtime/ktx/api/1.0.0-beta02.txt
new file mode 100644
index 0000000..d1e3b0e
--- /dev/null
+++ b/navigation/runtime/ktx/api/1.0.0-beta02.txt
@@ -0,0 +1,57 @@
+// Signature format: 3.0
+package androidx.navigation {
+
+  public final class ActivityKt {
+    ctor public ActivityKt();
+    method public static androidx.navigation.NavController findNavController(android.app.Activity, @IdRes int viewId);
+  }
+
+  public final class ActivityNavArgsLazyKt {
+    ctor public ActivityNavArgsLazyKt();
+    method @MainThread public static inline <reified Args extends androidx.navigation.NavArgs> androidx.navigation.NavArgsLazy<Args>! navArgs(android.app.Activity);
+  }
+
+  public final class ActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
+    ctor public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, @IdRes int id);
+    method public androidx.navigation.ActivityNavigator.Destination build();
+    method public String? getAction();
+    method public kotlin.reflect.KClass<? extends android.app.Activity>? getActivityClass();
+    method public android.net.Uri? getData();
+    method public String? getDataPattern();
+    method public void setAction(String? p);
+    method public void setActivityClass(kotlin.reflect.KClass<? extends android.app.Activity>? p);
+    method public void setData(android.net.Uri? p);
+    method public void setDataPattern(String? p);
+    property public final String? action;
+    property public final kotlin.reflect.KClass<? extends android.app.Activity>? activityClass;
+    property public final android.net.Uri? data;
+    property public final String? dataPattern;
+  }
+
+  public final class ActivityNavigatorDestinationBuilderKt {
+    ctor public ActivityNavigatorDestinationBuilderKt();
+    method public static inline void activity(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+  }
+
+  public final class ActivityNavigatorExtrasKt {
+    ctor public ActivityNavigatorExtrasKt();
+    method public static androidx.navigation.ActivityNavigator.Extras ActivityNavigatorExtras(android.support.v4.app.ActivityOptionsCompat? activityOptions = null, int flags = 0);
+  }
+
+  public final class NavControllerKt {
+    ctor public NavControllerKt();
+    method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, @IdRes int id = 0, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavHostKt {
+    ctor public NavHostKt();
+    method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, @IdRes int id = 0, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class ViewKt {
+    ctor public ViewKt();
+    method public static androidx.navigation.NavController findNavController(android.view.View);
+  }
+
+}
+
diff --git a/navigation/runtime/ktx/api/res-1.0.0-beta02.txt b/navigation/runtime/ktx/api/res-1.0.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/runtime/ktx/api/res-1.0.0-beta02.txt
diff --git a/navigation/runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt b/navigation/runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
index ae88c78..8aa18ad 100644
--- a/navigation/runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
+++ b/navigation/runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.os.Bundle
 import android.os.Parcel
+import android.os.Parcelable
 import androidx.navigation.test.R
 import androidx.navigation.testing.TestNavigator
 import androidx.navigation.testing.test
@@ -208,7 +209,7 @@
         val navigator = TestNavigator()
         navController.navigatorProvider.addNavigator(navigator)
         val graph = NavInflater(context, navController.navigatorProvider)
-                .inflate(R.navigation.nav_simple)
+            .inflate(R.navigation.nav_simple)
         navController.graph = graph
         navController.navigate(R.id.second_test)
 
@@ -227,6 +228,66 @@
     }
 
     @Test
+    fun testSaveRestoreStateBundleParceled() {
+        val context = ApplicationProvider.getApplicationContext() as Context
+        var navController = NavController(context)
+        val navigator = SaveStateTestNavigator()
+        navController.navigatorProvider.addNavigator(navigator)
+        navController.setGraph(R.navigation.nav_simple)
+
+        navigator.customParcel = CustomTestParcelable(TEST_ARG_VALUE)
+
+        val savedState = navController.saveState()
+
+        val parcel = Parcel.obtain()
+        savedState?.writeToParcel(parcel, 0)
+        parcel.setDataPosition(0)
+
+        val restoredState = Bundle.CREATOR.createFromParcel(parcel)
+
+        navController = NavController(context)
+        navController.navigatorProvider.addNavigator(navigator)
+
+        navController.restoreState(restoredState)
+        navController.setGraph(R.navigation.nav_simple)
+
+        // Ensure custom parcelable is present and can be read
+        assertThat(navigator.customParcel?.name).isEqualTo(TEST_ARG_VALUE)
+    }
+
+    @Test
+    fun testBackstackArgsBundleParceled() {
+        val context = ApplicationProvider.getApplicationContext() as Context
+        var navController = NavController(context)
+        val navigator = SaveStateTestNavigator()
+        navController.navigatorProvider.addNavigator(navigator)
+
+        val backStackArg1 = Bundle()
+        backStackArg1.putParcelable(TEST_ARG, CustomTestParcelable(TEST_ARG_VALUE))
+        navController.setGraph(R.navigation.nav_arguments)
+        navController.navigate(R.id.second_test, backStackArg1)
+
+        val savedState = navController.saveState()
+
+        val parcel = Parcel.obtain()
+        savedState?.writeToParcel(parcel, 0)
+        parcel.setDataPosition(0)
+
+        val restoredState = Bundle.CREATOR.createFromParcel(parcel)
+
+        navController = NavController(context)
+        navController.navigatorProvider.addNavigator(navigator)
+
+        navController.restoreState(restoredState)
+        navController.setGraph(R.navigation.nav_arguments)
+
+        navController.addOnDestinationChangedListener { _, _, arguments ->
+            assertThat(arguments?.getParcelable<CustomTestParcelable>(TEST_ARG)?.name)
+                .isEqualTo(TEST_ARG_VALUE)
+        }
+    }
+
+    @Test
     fun testNavigateWithNoDefaultValue() {
         val returnedArgs = navigateWithArgs(null)
 
@@ -658,18 +719,41 @@
 
     companion object {
         private const val STATE_SAVED_COUNT = "saved_count"
+        private const val TEST_PARCEL = "test_parcel"
     }
 
     var saveStateCount = 0
+    var customParcel: CustomTestParcelable? = null
 
     override fun onSaveState(): Bundle? {
         saveStateCount += 1
         val state = Bundle()
         state.putInt(STATE_SAVED_COUNT, saveStateCount)
+        state.putParcelable(TEST_PARCEL, customParcel)
         return state
     }
 
     override fun onRestoreState(savedState: Bundle) {
         saveStateCount = savedState.getInt(STATE_SAVED_COUNT)
+        customParcel = savedState.getParcelable(TEST_PARCEL)
     }
 }
+
+/**
+ * [CustomTestParcelable] that helps testing bundled custom parcels
+ */
+data class CustomTestParcelable(val name: String?) : Parcelable {
+    constructor(parcel: Parcel) : this(parcel.readString())
+
+    override fun writeToParcel(dest: Parcel?, flags: Int) {
+        dest?.writeString(name)
+    }
+
+    override fun describeContents() = 0
+
+    companion object CREATOR : Parcelable.Creator<CustomTestParcelable> {
+        override fun createFromParcel(parcel: Parcel) = CustomTestParcelable(parcel)
+
+        override fun newArray(size: Int): Array<CustomTestParcelable?> = arrayOfNulls(size)
+    }
+}
\ No newline at end of file
diff --git a/navigation/runtime/src/main/java/androidx/navigation/NavController.java b/navigation/runtime/src/main/java/androidx/navigation/NavController.java
index 2d318cf..f3faff4 100644
--- a/navigation/runtime/src/main/java/androidx/navigation/NavController.java
+++ b/navigation/runtime/src/main/java/androidx/navigation/NavController.java
@@ -492,6 +492,9 @@
                     throw new IllegalStateException("unknown destination during restore: "
                             + mContext.getResources().getResourceName(destinationId));
                 }
+                if (args != null) {
+                    args.setClassLoader(mContext.getClassLoader());
+                }
                 mBackStack.add(new NavBackStackEntry(node, args));
             }
             mBackStackIdsToRestore = null;
@@ -939,6 +942,8 @@
             return;
         }
 
+        navState.setClassLoader(mContext.getClassLoader());
+
         mNavigatorStateToRestore = navState.getBundle(KEY_NAVIGATOR_STATE);
         mBackStackIdsToRestore = navState.getIntArray(KEY_BACK_STACK_IDS);
         mBackStackArgsToRestore = navState.getParcelableArray(KEY_BACK_STACK_ARGS);
diff --git a/navigation/safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/java/JavaTypes.kt b/navigation/safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/java/JavaTypes.kt
index 2bde474..2c844d1 100644
--- a/navigation/safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/java/JavaTypes.kt
+++ b/navigation/safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/java/JavaTypes.kt
@@ -58,6 +58,7 @@
 internal val BUNDLE_CLASSNAME: ClassName = ClassName.get("android.os", "Bundle")
 internal val PARCELABLE_CLASSNAME = ClassName.get("android.os", "Parcelable")
 internal val SERIALIZABLE_CLASSNAME = ClassName.get("java.io", "Serializable")
+internal val SYSTEM_CLASSNAME = ClassName.get("java.lang", "System")
 
 internal abstract class Annotations {
     abstract val NULLABLE_CLASSNAME: ClassName
@@ -108,10 +109,22 @@
             )
         }.endControlFlow()
     }
-    is ObjectArrayType -> builder.addStatement(
-        "$N = ($T) $N.$N($S)",
-        lValue, typeName(), bundle, bundleGetMethod(), arg.name
-    )
+    is ObjectArrayType -> builder.apply {
+        val arrayName = "__array"
+        val baseType = (arg.type.typeName() as ArrayTypeName).componentType
+        addStatement("$T[] $N = $N.$N($S)",
+            PARCELABLE_CLASSNAME, arrayName, bundle, bundleGetMethod(), arg.name)
+        beginControlFlow("if ($N != null)", arrayName).apply {
+            addStatement("$N = new $T[$N.length]", lValue, baseType, arrayName)
+            addStatement("$T.arraycopy($N, 0, $N, 0, $N.length)",
+                SYSTEM_CLASSNAME, arrayName, lValue, arrayName
+            )
+        }
+        nextControlFlow("else").apply {
+            addStatement("$N = null", lValue)
+        }
+        endControlFlow()
+    }
     else -> builder.addStatement(
         "$N = $N.$N($S)",
         lValue,
diff --git a/navigation/safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/kotlin/KotlinTypes.kt b/navigation/safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/kotlin/KotlinTypes.kt
index 35376d9..4baae90 100644
--- a/navigation/safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/kotlin/KotlinTypes.kt
+++ b/navigation/safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/kotlin/KotlinTypes.kt
@@ -51,6 +51,7 @@
 import com.squareup.kotlinpoet.FunSpec
 import com.squareup.kotlinpoet.INT
 import com.squareup.kotlinpoet.LONG
+import com.squareup.kotlinpoet.ParameterizedTypeName
 import com.squareup.kotlinpoet.TypeName
 import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
 import com.squareup.kotlinpoet.asTypeName
@@ -91,10 +92,12 @@
         )
         endControlFlow()
     }
-    is ObjectArrayType -> builder.addStatement(
-        "%L = %L.%L(%S) as %T",
-        lValue, bundle, bundleGetMethod(), arg.name, arg.type.typeName().copy(nullable = true)
-    )
+    is ObjectArrayType -> builder.apply {
+        val baseType = (arg.type.typeName() as ParameterizedTypeName).typeArguments.first()
+        addStatement(
+            "%L = %L.%L(%S)?.map { it as %T }?.toTypedArray()",
+            lValue, bundle, bundleGetMethod(), arg.name, baseType)
+    }
     else -> builder.addStatement(
         "%L = %L.%L(%S)",
         lValue,
diff --git a/navigation/safe-args-generator/src/tests/test-data/expected/java_nav_writer_test/MainFragmentArgs.java b/navigation/safe-args-generator/src/tests/test-data/expected/java_nav_writer_test/MainFragmentArgs.java
index 54d6a4d..e0add51 100644
--- a/navigation/safe-args-generator/src/tests/test-data/expected/java_nav_writer_test/MainFragmentArgs.java
+++ b/navigation/safe-args-generator/src/tests/test-data/expected/java_nav_writer_test/MainFragmentArgs.java
@@ -28,6 +28,7 @@
 import java.lang.Override;
 import java.lang.String;
 import java.lang.SuppressWarnings;
+import java.lang.System;
 import java.nio.file.AccessMode;
 import java.util.HashMap;
 
@@ -83,7 +84,13 @@
         }
         if (bundle.containsKey("objectArrayArg")) {
             ActivityInfo[] objectArrayArg;
-            objectArrayArg = (ActivityInfo[]) bundle.getParcelableArray("objectArrayArg");
+            Parcelable[] __array = bundle.getParcelableArray("objectArrayArg");
+            if (__array != null) {
+                objectArrayArg = new ActivityInfo[__array.length];
+                System.arraycopy(__array, 0, objectArrayArg, 0, __array.length);
+            } else {
+                objectArrayArg = null;
+            }
             if (objectArrayArg == null) {
                 throw new IllegalArgumentException("Argument \"objectArrayArg\" is marked as non-null but was passed a null value.");
             }
diff --git a/navigation/safe-args-generator/src/tests/test-data/expected/kotlin_nav_writer_test/MainFragmentArgs.kt b/navigation/safe-args-generator/src/tests/test-data/expected/kotlin_nav_writer_test/MainFragmentArgs.kt
index f87f02b..3287f75 100644
--- a/navigation/safe-args-generator/src/tests/test-data/expected/kotlin_nav_writer_test/MainFragmentArgs.kt
+++ b/navigation/safe-args-generator/src/tests/test-data/expected/kotlin_nav_writer_test/MainFragmentArgs.kt
@@ -94,8 +94,8 @@
             }
             val __objectArrayArg : Array<ActivityInfo>?
             if (bundle.containsKey("objectArrayArg")) {
-                __objectArrayArg = bundle.getParcelableArray("objectArrayArg") as
-                        Array<ActivityInfo>?
+                __objectArrayArg = bundle.getParcelableArray("objectArrayArg")?.map { it as
+                        ActivityInfo }?.toTypedArray()
                 if (__objectArrayArg == null) {
                     throw IllegalArgumentException("Argument \"objectArrayArg\" is marked as non-null but was passed a null value.")
                 }
diff --git a/navigation/ui/api/1.0.0-beta02.txt b/navigation/ui/api/1.0.0-beta02.txt
new file mode 100644
index 0000000..af2f1c1
--- /dev/null
+++ b/navigation/ui/api/1.0.0-beta02.txt
@@ -0,0 +1,42 @@
+// Signature format: 3.0
+package androidx.navigation.ui {
+
+  public final class AppBarConfiguration {
+    method public android.support.v4.widget.DrawerLayout? getDrawerLayout();
+    method public androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? getFallbackOnNavigateUpListener();
+    method public java.util.Set<java.lang.Integer> getTopLevelDestinations();
+  }
+
+  public static final class AppBarConfiguration.Builder {
+    ctor public AppBarConfiguration.Builder(androidx.navigation.NavGraph);
+    ctor public AppBarConfiguration.Builder(android.view.Menu);
+    ctor public AppBarConfiguration.Builder(int...);
+    ctor public AppBarConfiguration.Builder(java.util.Set<java.lang.Integer>);
+    method public androidx.navigation.ui.AppBarConfiguration build();
+    method public androidx.navigation.ui.AppBarConfiguration.Builder setDrawerLayout(android.support.v4.widget.DrawerLayout?);
+    method public androidx.navigation.ui.AppBarConfiguration.Builder setFallbackOnNavigateUpListener(androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener?);
+  }
+
+  public static interface AppBarConfiguration.OnNavigateUpListener {
+    method public boolean onNavigateUp();
+  }
+
+  public final class NavigationUI {
+    method public static boolean navigateUp(androidx.navigation.NavController, android.support.v4.widget.DrawerLayout?);
+    method public static boolean navigateUp(androidx.navigation.NavController, androidx.navigation.ui.AppBarConfiguration);
+    method public static boolean onNavDestinationSelected(android.view.MenuItem, androidx.navigation.NavController);
+    method public static void setupActionBarWithNavController(android.support.v7.app.AppCompatActivity, androidx.navigation.NavController);
+    method public static void setupActionBarWithNavController(android.support.v7.app.AppCompatActivity, androidx.navigation.NavController, android.support.v4.widget.DrawerLayout?);
+    method public static void setupActionBarWithNavController(android.support.v7.app.AppCompatActivity, androidx.navigation.NavController, androidx.navigation.ui.AppBarConfiguration);
+    method public static void setupWithNavController(android.support.v7.widget.Toolbar, androidx.navigation.NavController);
+    method public static void setupWithNavController(android.support.v7.widget.Toolbar, androidx.navigation.NavController, android.support.v4.widget.DrawerLayout?);
+    method public static void setupWithNavController(android.support.v7.widget.Toolbar, androidx.navigation.NavController, androidx.navigation.ui.AppBarConfiguration);
+    method public static void setupWithNavController(android.support.design.widget.CollapsingToolbarLayout, android.support.v7.widget.Toolbar, androidx.navigation.NavController);
+    method public static void setupWithNavController(android.support.design.widget.CollapsingToolbarLayout, android.support.v7.widget.Toolbar, androidx.navigation.NavController, android.support.v4.widget.DrawerLayout?);
+    method public static void setupWithNavController(android.support.design.widget.CollapsingToolbarLayout, android.support.v7.widget.Toolbar, androidx.navigation.NavController, androidx.navigation.ui.AppBarConfiguration);
+    method public static void setupWithNavController(android.support.design.widget.NavigationView, androidx.navigation.NavController);
+    method public static void setupWithNavController(android.support.design.widget.BottomNavigationView, androidx.navigation.NavController);
+  }
+
+}
+
diff --git a/navigation/ui/api/res-1.0.0-beta02.txt b/navigation/ui/api/res-1.0.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/ui/api/res-1.0.0-beta02.txt
diff --git a/navigation/ui/ktx/api/1.0.0-beta02.txt b/navigation/ui/ktx/api/1.0.0-beta02.txt
new file mode 100644
index 0000000..578c40c
--- /dev/null
+++ b/navigation/ui/ktx/api/1.0.0-beta02.txt
@@ -0,0 +1,51 @@
+// Signature format: 3.0
+package androidx.navigation.ui {
+
+  public final class ActivityKt {
+    ctor public ActivityKt();
+    method public static void setupActionBarWithNavController(android.support.v7.app.AppCompatActivity, androidx.navigation.NavController navController, android.support.v4.widget.DrawerLayout? drawerLayout);
+    method public static void setupActionBarWithNavController(android.support.v7.app.AppCompatActivity, androidx.navigation.NavController navController, androidx.navigation.ui.AppBarConfiguration configuration = AppBarConfiguration(navController.graph));
+  }
+
+  public final class AppBarConfigurationKt {
+    ctor public AppBarConfigurationKt();
+    method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(androidx.navigation.NavGraph navGraph, android.support.v4.widget.DrawerLayout? drawerLayout = null, kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener = { false });
+    method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(android.view.Menu topLevelMenu, android.support.v4.widget.DrawerLayout? drawerLayout = null, kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener = { false });
+    method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(java.util.Set<java.lang.Integer> topLevelDestinationIds, android.support.v4.widget.DrawerLayout? drawerLayout = null, kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener = { false });
+  }
+
+  public final class BottomNavigationViewKt {
+    ctor public BottomNavigationViewKt();
+    method public static void setupWithNavController(android.support.design.widget.BottomNavigationView, androidx.navigation.NavController navController);
+  }
+
+  public final class CollapsingToolbarLayoutKt {
+    ctor public CollapsingToolbarLayoutKt();
+    method public static void setupWithNavController(android.support.design.widget.CollapsingToolbarLayout, android.support.v7.widget.Toolbar toolbar, androidx.navigation.NavController navController, android.support.v4.widget.DrawerLayout? drawerLayout);
+    method public static void setupWithNavController(android.support.design.widget.CollapsingToolbarLayout, android.support.v7.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.navigation.ui.AppBarConfiguration configuration = AppBarConfiguration(navController.graph));
+  }
+
+  public final class MenuItemKt {
+    ctor public MenuItemKt();
+    method public static boolean onNavDestinationSelected(android.view.MenuItem, androidx.navigation.NavController navController);
+  }
+
+  public final class NavControllerKt {
+    ctor public NavControllerKt();
+    method public static boolean navigateUp(androidx.navigation.NavController, android.support.v4.widget.DrawerLayout? drawerLayout);
+    method public static boolean navigateUp(androidx.navigation.NavController, androidx.navigation.ui.AppBarConfiguration appBarConfiguration);
+  }
+
+  public final class NavigationViewKt {
+    ctor public NavigationViewKt();
+    method public static void setupWithNavController(android.support.design.widget.NavigationView, androidx.navigation.NavController navController);
+  }
+
+  public final class ToolbarKt {
+    ctor public ToolbarKt();
+    method public static void setupWithNavController(android.support.v7.widget.Toolbar, androidx.navigation.NavController navController, android.support.v4.widget.DrawerLayout? drawerLayout);
+    method public static void setupWithNavController(android.support.v7.widget.Toolbar, androidx.navigation.NavController navController, androidx.navigation.ui.AppBarConfiguration configuration = AppBarConfiguration(navController.graph));
+  }
+
+}
+
diff --git a/navigation/ui/ktx/api/res-1.0.0-beta02.txt b/navigation/ui/ktx/api/res-1.0.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/ui/ktx/api/res-1.0.0-beta02.txt
diff --git a/preference/build.gradle b/preference/build.gradle
index 1f750ef..1d2bff0 100644
--- a/preference/build.gradle
+++ b/preference/build.gradle
@@ -23,13 +23,10 @@
 }
 
 dependencies {
-    // TODO: change to 1.1.0-alpha02 after release
-    api(project(":appcompat"))
-    // TODO: change to 1.1.0-alpha04 after release
-    api(project(":core"))
+    api("androidx.appcompat:appcompat:1.1.0-alpha02")
+    api("androidx.core:core:1.1.0-alpha04")
     implementation("androidx.collection:collection:1.0.0")
-    // TODO: change to 1.1.0-alpha04 after release
-    api(project(":fragment"))
+    api("androidx.fragment:fragment:1.1.0-alpha04")
     api("androidx.recyclerview:recyclerview:1.0.0")
 
     androidTestImplementation(TEST_EXT_JUNIT)