Merge "Remove invalid owner from text module." into androidx-crane-dev
diff --git a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
index ec393ba..c1b0df4 100644
--- a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
@@ -30,6 +30,8 @@
     prebuilts(LibraryGroups.APPCOMPAT, "1.1.0-alpha05")
     prebuilts(LibraryGroups.ARCH_CORE, "2.1.0-beta01")
     prebuilts(LibraryGroups.ASYNCLAYOUTINFLATER, "1.0.0")
+    ignore(LibraryGroups.BENCHMARK.group, "benchmark-gradle-plugin")
+    prebuilts(LibraryGroups.BENCHMARK, "1.0.0-alpha01")
     prebuilts(LibraryGroups.BIOMETRIC, "biometric", "1.0.0-alpha04")
     prebuilts(LibraryGroups.BROWSER, "1.0.0")
     ignore(LibraryGroups.CAMERA.group, "camera-view")
@@ -81,10 +83,6 @@
     prebuilts(LibraryGroups.MEDIA, "media-widget", "1.0.0-alpha06")
     ignore(LibraryGroups.MEDIA2.group, "media2-widget")
     ignore(LibraryGroups.MEDIA2.group, "media2-exoplayer")
-    // TODO: Reenable to use media2-{common,player,session} prebuilts (b/130839413)
-    ignore(LibraryGroups.MEDIA2.group, "media2-common")
-    ignore(LibraryGroups.MEDIA2.group, "media2-player")
-    ignore(LibraryGroups.MEDIA2.group, "media2-session")
     prebuilts(LibraryGroups.MEDIA2, "1.0.0-beta01")
     prebuilts(LibraryGroups.MEDIAROUTER, "1.1.0-beta01")
     ignore(LibraryGroups.NAVIGATION.group, "navigation-testing")
@@ -99,18 +97,19 @@
     prebuilts(LibraryGroups.RECOMMENDATION, "1.0.0")
     prebuilts(LibraryGroups.RECYCLERVIEW, "recyclerview", "1.1.0-alpha05")
     prebuilts(LibraryGroups.RECYCLERVIEW, "recyclerview-selection", "1.1.0-alpha05")
-    prebuilts(LibraryGroups.REMOTECALLBACK, "1.0.0-alpha01")
+    prebuilts(LibraryGroups.REMOTECALLBACK, "1.0.0-alpha02")
     ignore(LibraryGroups.ROOM.group, "room-common-java8")
     prebuilts(LibraryGroups.ROOM, "2.1.0-beta01")
     prebuilts(LibraryGroups.SAVEDSTATE, "1.0.0-beta01")
+    prebuilts(LibraryGroups.SECURITY, "1.0.0-alpha01")
     prebuilts(LibraryGroups.SHARETARGET, "1.0.0-alpha01")
-    prebuilts(LibraryGroups.SLICE, "slice-builders", "1.0.0")
-    prebuilts(LibraryGroups.SLICE, "slice-builders-ktx", "1.0.0-alpha6")
-    prebuilts(LibraryGroups.SLICE, "slice-core", "1.0.0")
+    prebuilts(LibraryGroups.SLICE, "slice-builders", "1.1.0-alpha01")
+    prebuilts(LibraryGroups.SLICE, "slice-builders-ktx", "1.0.0-alpha07")
+    prebuilts(LibraryGroups.SLICE, "slice-core", "1.1.0-alpha01")
     // TODO: land prebuilts
 //    prebuilts(LibraryGroups.SLICE.group, "slice-test", "1.0.0")
     ignore(LibraryGroups.SLICE.group, "slice-test")
-    prebuilts(LibraryGroups.SLICE, "slice-view", "1.0.0")
+    prebuilts(LibraryGroups.SLICE, "slice-view", "1.1.0-alpha01")
     prebuilts(LibraryGroups.SLIDINGPANELAYOUT, "1.0.0")
     prebuilts(LibraryGroups.SWIPEREFRESHLAYOUT, "1.1.0-alpha01")
     prebuilts(LibraryGroups.TEXTCLASSIFIER, "1.0.0-alpha02")
diff --git a/camera/camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java b/camera/camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
index a7b81cc..819b3b6 100644
--- a/camera/camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
+++ b/camera/camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
@@ -480,7 +480,8 @@
         }
     }
 
-    @Test
+    // Skipping test due to b/132108192. Add back once test has been fixed.
+    // @Test
     public void camera2InteropCaptureSessionCallbacks() throws InterruptedException {
         ImageCaptureConfig.Builder configBuilder =
                 new ImageCaptureConfig.Builder().setCallbackHandler(mHandler);
@@ -506,6 +507,8 @@
                 requestCaptor.capture(),
                 any(TotalCaptureResult.class));
         CaptureRequest captureRequest = requestCaptor.getValue(); // Obtains the last value.
+        // TODO This method removed temporary due to the side effect of aosp/943904. It's needed
+        //  keep tracking.
         assertThat(captureRequest.get(CaptureRequest.CONTROL_CAPTURE_INTENT))
                 .isEqualTo(CaptureRequest.CONTROL_CAPTURE_INTENT_STILL_CAPTURE);
     }
diff --git a/camera/camera2/src/main/java/androidx/camera/camera2/impl/compat/CameraDeviceCompat.java b/camera/camera2/src/main/java/androidx/camera/camera2/impl/compat/CameraDeviceCompat.java
new file mode 100644
index 0000000..d6bc064
--- /dev/null
+++ b/camera/camera2/src/main/java/androidx/camera/camera2/impl/compat/CameraDeviceCompat.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 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.camera.camera2.impl.compat;
+
+import android.annotation.TargetApi;
+import android.hardware.camera2.CameraDevice;
+
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+
+/**
+ * Helper for accessing features in {@link CameraDevice} in a backwards compatible fashion.
+ *
+ * @hide Will be unhidden once some methods are implemented
+ */
+@RestrictTo(Scope.LIBRARY)
+@TargetApi(21)
+public final class CameraDeviceCompat {
+
+    /**
+     * Standard camera operation mode.
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public static final int SESSION_OPERATION_MODE_NORMAL =
+            0; // ICameraDeviceUser.NORMAL_MODE;
+
+    /**
+     * Constrained high-speed operation mode.
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public static final int SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED =
+            1; // ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE;
+}
diff --git a/camera/camera2/src/main/java/androidx/camera/camera2/impl/compat/package-info.java b/camera/camera2/src/main/java/androidx/camera/camera2/impl/compat/package-info.java
new file mode 100644
index 0000000..f6409d6
--- /dev/null
+++ b/camera/camera2/src/main/java/androidx/camera/camera2/impl/compat/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2019 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.
+ */
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+package androidx.camera.camera2.impl.compat;
+
+import androidx.annotation.RestrictTo;
diff --git a/camera/camera2/src/main/java/androidx/camera/camera2/impl/compat/params/SessionConfigurationCompat.java b/camera/camera2/src/main/java/androidx/camera/camera2/impl/compat/params/SessionConfigurationCompat.java
new file mode 100644
index 0000000..7afc02a
--- /dev/null
+++ b/camera/camera2/src/main/java/androidx/camera/camera2/impl/compat/params/SessionConfigurationCompat.java
@@ -0,0 +1,480 @@
+/*
+ * Copyright 2019 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.camera.camera2.impl.compat.params;
+
+import android.annotation.TargetApi;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.InputConfiguration;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.SessionConfiguration;
+import android.os.Build;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+import androidx.camera.camera2.impl.compat.CameraDeviceCompat;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Helper for accessing features in SessionConfiguration in a backwards compatible fashion.
+ */
+@TargetApi(21)
+public final class SessionConfigurationCompat {
+
+    /**
+     * A regular session type containing instances of {@link OutputConfigurationCompat} running
+     * at regular non high speed FPS ranges and optionally {@link InputConfigurationCompat} for
+     * reprocessable sessions.
+     *
+     * @see CameraDevice#createCaptureSession
+     * @see CameraDevice#createReprocessableCaptureSession
+     */
+    public static final int SESSION_REGULAR = CameraDeviceCompat.SESSION_OPERATION_MODE_NORMAL;
+    /**
+     * A high speed session type that can only contain instances of
+     * {@link OutputConfigurationCompat}.
+     * The outputs can run using high speed FPS ranges. Calls to {@link #setInputConfiguration}
+     * are not supported.
+     *
+     * @see CameraDevice#createConstrainedHighSpeedCaptureSession
+     */
+    public static final int SESSION_HIGH_SPEED =
+            CameraDeviceCompat.SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED;
+    private final SessionConfigurationCompatImpl mImpl;
+
+    /**
+     * Create a new {@link SessionConfigurationCompat}.
+     *
+     * @param sessionType   The session type.
+     * @param outputsCompat A list of output configurations for the capture session.
+     * @param executor      The executor which should be used to invoke the callback. In general
+     *                      it is
+     *                      recommended that camera operations are not done on the main (UI) thread.
+     * @param cb            A state callback interface implementation.
+     * @see #SESSION_REGULAR
+     * @see #SESSION_HIGH_SPEED
+     */
+    public SessionConfigurationCompat(@SessionMode int sessionType,
+            @NonNull List<OutputConfigurationCompat> outputsCompat,
+            @NonNull /* @CallbackExecutor */ Executor executor,
+            @NonNull CameraCaptureSession.StateCallback cb) {
+        if (Build.VERSION.SDK_INT < 28) {
+            mImpl = new SessionConfigurationCompatBaseImpl(sessionType, outputsCompat, executor,
+                    cb);
+        } else {
+            mImpl = new SessionConfigurationCompatApi28Impl(sessionType, outputsCompat, executor,
+                    cb);
+        }
+    }
+
+    private SessionConfigurationCompat(@NonNull SessionConfigurationCompatImpl impl) {
+        mImpl = impl;
+    }
+
+    /**
+     * Creates an instance from a framework android.hardware.camera2.params.SessionConfiguration
+     * object.
+     *
+     * <p>This method always returns {@code null} on API &lt;= 27.</p>
+     *
+     * @param sessionConfiguration an android.hardware.camera2.params.SessionConfiguration object,
+     *                             or {@code null} if none.
+     * @return an equivalent {@link SessionConfigurationCompat} object, or {@code null} if not
+     * supported.
+     */
+    @Nullable
+    public static SessionConfigurationCompat wrap(@Nullable Object sessionConfiguration) {
+        if (sessionConfiguration == null) {
+            return null;
+        }
+        if (Build.VERSION.SDK_INT < 28) {
+            return null;
+        }
+
+        return new SessionConfigurationCompat(
+                new SessionConfigurationCompatApi28Impl(sessionConfiguration));
+    }
+
+    @RequiresApi(24)
+    static List<OutputConfigurationCompat> transformToCompat(
+            @NonNull List<OutputConfiguration> outputConfigurations) {
+        ArrayList<OutputConfigurationCompat> outList = new ArrayList<>(outputConfigurations.size());
+        for (OutputConfiguration outputConfiguration : outputConfigurations) {
+            outList.add(OutputConfigurationCompat.wrap(outputConfiguration));
+        }
+
+        return outList;
+    }
+
+    @RequiresApi(24)
+    static List<OutputConfiguration> transformFromCompat(
+            @NonNull List<OutputConfigurationCompat> outputConfigurations) {
+        ArrayList<OutputConfiguration> outList = new ArrayList<>(outputConfigurations.size());
+        for (OutputConfigurationCompat outputConfiguration : outputConfigurations) {
+            outList.add((OutputConfiguration) outputConfiguration.unwrap());
+        }
+
+        return outList;
+    }
+
+    /**
+     * Retrieve the type of the capture session.
+     *
+     * @return The capture session type.
+     */
+    @SessionMode
+    public int getSessionType() {
+        return mImpl.getSessionType();
+    }
+
+    /**
+     * Retrieve the {@link OutputConfigurationCompat} list for the capture session.
+     *
+     * @return A list of output configurations for the capture session.
+     */
+    public List<OutputConfigurationCompat> getOutputConfigurations() {
+        return mImpl.getOutputConfigurations();
+    }
+
+    /**
+     * Retrieve the {@link CameraCaptureSession.StateCallback} for the capture session.
+     *
+     * @return A state callback interface implementation.
+     */
+    public CameraCaptureSession.StateCallback getStateCallback() {
+        return mImpl.getStateCallback();
+    }
+
+    /**
+     * Retrieve the {@link Executor} for the capture session.
+     *
+     * @return The Executor on which the callback will be invoked.
+     */
+    public Executor getExecutor() {
+        return mImpl.getExecutor();
+    }
+
+    /**
+     * Retrieve the {@link InputConfigurationCompat}.
+     *
+     * @return The capture session input configuration.
+     */
+    public InputConfigurationCompat getInputConfiguration() {
+        return mImpl.getInputConfiguration();
+    }
+
+    /**
+     * Sets the {@link InputConfigurationCompat} for a reprocessable session. Input configuration
+     * are not supported for {@link #SESSION_HIGH_SPEED}.
+     *
+     * @param input Input configuration.
+     * @throws UnsupportedOperationException In case it is called for {@link #SESSION_HIGH_SPEED}
+     *                                       type session configuration.
+     */
+    public void setInputConfiguration(@NonNull InputConfigurationCompat input) {
+        mImpl.setInputConfiguration(input);
+    }
+
+    /**
+     * Retrieve the session wide camera parameters (see {@link CaptureRequest}).
+     *
+     * @return A capture request that includes the initial values for any available
+     * session wide capture keys.
+     */
+    public CaptureRequest getSessionParameters() {
+        return mImpl.getSessionParameters();
+    }
+
+    /**
+     * Sets the session wide camera parameters (see {@link CaptureRequest}). This argument can
+     * be set for every supported session type and will be passed to the camera device as part
+     * of the capture session initialization. Session parameters are a subset of the available
+     * capture request parameters (see {@code CameraCharacteristics.getAvailableSessionKeys})
+     * and their application can introduce internal camera delays. To improve camera performance
+     * it is suggested to change them sparingly within the lifetime of the capture session and
+     * to pass their initial values as part of this method.
+     *
+     * @param params A capture request that includes the initial values for any available
+     *               session wide capture keys. Tags (see {@link CaptureRequest.Builder#setTag}) and
+     *               output targets (see {@link CaptureRequest.Builder#addTarget}) are ignored if
+     *               set. Parameter values not part of
+     *               {@code CameraCharacteristics.getAvailableSessionKeys} will also be ignored. It
+     *               is recommended to build the session parameters using the same template type as
+     *               the initial capture request, so that the session and initial request parameters
+     *               match as much as possible.
+     */
+    public void setSessionParameters(CaptureRequest params) {
+        mImpl.setSessionParameters(params);
+    }
+
+    /**
+     * Gets the underlying framework android.hardware.camera2.params.SessionConfiguration object.
+     *
+     * <p>This method always returns {@code null} on API &lt;= 27.</p>
+     *
+     * @return an equivalent android.hardware.camera2.params.SessionConfiguration object, or
+     * {@code null} if not supported.
+     */
+    @Nullable
+    public Object unwrap() {
+        return mImpl.getSessionConfiguration();
+    }
+
+    @Override
+    public boolean equals(@Nullable Object obj) {
+        if (!(obj instanceof SessionConfigurationCompat)) {
+            return false;
+        }
+
+        return mImpl.equals(((SessionConfigurationCompat) obj).mImpl);
+    }
+
+    /** @hide */
+    @RestrictTo(Scope.LIBRARY)
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value =
+            {SESSION_REGULAR, SESSION_HIGH_SPEED})
+    public @interface SessionMode {
+    }
+
+    private interface SessionConfigurationCompatImpl {
+        @SessionMode
+        int getSessionType();
+
+        List<OutputConfigurationCompat> getOutputConfigurations();
+
+        CameraCaptureSession.StateCallback getStateCallback();
+
+        Executor getExecutor();
+
+        InputConfigurationCompat getInputConfiguration();
+
+        void setInputConfiguration(@NonNull InputConfigurationCompat input);
+
+        CaptureRequest getSessionParameters();
+
+        void setSessionParameters(CaptureRequest params);
+
+        @Nullable
+        Object getSessionConfiguration();
+    }
+
+    private static final class SessionConfigurationCompatBaseImpl implements
+            SessionConfigurationCompatImpl {
+
+        private final List<OutputConfigurationCompat> mOutputConfigurations;
+        private final CameraCaptureSession.StateCallback mStateCallback;
+        private final Executor mExecutor;
+        private int mSessionType;
+        private InputConfigurationCompat mInputConfig = null;
+        private CaptureRequest mSessionParameters = null;
+
+        SessionConfigurationCompatBaseImpl(@SessionMode int sessionType,
+                @NonNull List<OutputConfigurationCompat> outputs,
+                @NonNull /* @CallbackExecutor */ Executor executor,
+                @NonNull CameraCaptureSession.StateCallback cb) {
+            mSessionType = sessionType;
+            mOutputConfigurations = Collections.unmodifiableList(new ArrayList<>(outputs));
+            mStateCallback = cb;
+            mExecutor = executor;
+        }
+
+        @Override
+        public int getSessionType() {
+            return mSessionType;
+        }
+
+        @Override
+        public List<OutputConfigurationCompat> getOutputConfigurations() {
+            return mOutputConfigurations;
+        }
+
+        @Override
+        public CameraCaptureSession.StateCallback getStateCallback() {
+            return mStateCallback;
+        }
+
+        @Override
+        public Executor getExecutor() {
+            return mExecutor;
+        }
+
+        @Nullable
+        @Override
+        public InputConfigurationCompat getInputConfiguration() {
+            return mInputConfig;
+        }
+
+        @Override
+        public void setInputConfiguration(@NonNull InputConfigurationCompat input) {
+            if (mSessionType != SESSION_HIGH_SPEED) {
+                mInputConfig = input;
+            } else {
+                throw new UnsupportedOperationException(
+                        "Method not supported for high speed session types");
+            }
+        }
+
+        @Override
+        public CaptureRequest getSessionParameters() {
+            return mSessionParameters;
+        }
+
+        @Override
+        public void setSessionParameters(CaptureRequest params) {
+            mSessionParameters = params;
+        }
+
+        @Nullable
+        @Override
+        public Object getSessionConfiguration() {
+            return null;
+        }
+
+        @Override
+        public boolean equals(@Nullable Object obj) {
+            if (this == obj) {
+                return true;
+            } else if (obj instanceof SessionConfigurationCompatBaseImpl) {
+                SessionConfigurationCompatBaseImpl other = (SessionConfigurationCompatBaseImpl) obj;
+                if (mInputConfig != other.mInputConfig
+                        || mSessionType != other.mSessionType
+                        || mOutputConfigurations.size() != other.mOutputConfigurations.size()) {
+                    return false;
+                }
+
+                for (int i = 0; i < mOutputConfigurations.size(); i++) {
+                    if (!mOutputConfigurations.get(i).equals(other.mOutputConfigurations.get(i))) {
+                        return false;
+                    }
+                }
+
+                return true;
+            }
+
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            int h = 1;
+            // Strength reduction; in case the compiler has illusions about divisions being faster
+            h = ((h << 5) - h)
+                    ^ mOutputConfigurations.hashCode(); // (h * 31) XOR mOutputConfigurations
+            // .hashCode()
+            h = ((h << 5) - h) ^ (mInputConfig == null ? 0
+                    : mInputConfig.hashCode()); // (h * 31) XOR mInputConfig.hashCode()
+            h = ((h << 5) - h) ^ mSessionType; // (h * 31) XOR mSessionType
+
+            return h;
+        }
+    }
+
+    @RequiresApi(28)
+    private static final class SessionConfigurationCompatApi28Impl implements
+            SessionConfigurationCompatImpl {
+
+        private final SessionConfiguration mObject;
+        private final List<OutputConfigurationCompat> mOutputConfigurations;
+
+        SessionConfigurationCompatApi28Impl(@NonNull Object sessionConfiguration) {
+            mObject = (SessionConfiguration) sessionConfiguration;
+            mOutputConfigurations = Collections.unmodifiableList(transformToCompat(
+                    ((SessionConfiguration) sessionConfiguration).getOutputConfigurations()));
+        }
+
+        SessionConfigurationCompatApi28Impl(@SessionMode int sessionType,
+                @NonNull List<OutputConfigurationCompat> outputs,
+                @NonNull /* @CallbackExecutor */ Executor executor,
+                @NonNull CameraCaptureSession.StateCallback cb) {
+            this(new SessionConfiguration(sessionType, transformFromCompat(outputs), executor, cb));
+        }
+
+        @Override
+        public int getSessionType() {
+            return mObject.getSessionType();
+        }
+
+        @Override
+        public List<OutputConfigurationCompat> getOutputConfigurations() {
+            // Return cached compat version of list
+            return mOutputConfigurations;
+        }
+
+        @Override
+        public CameraCaptureSession.StateCallback getStateCallback() {
+            return mObject.getStateCallback();
+        }
+
+        @Override
+        public Executor getExecutor() {
+            return mObject.getExecutor();
+        }
+
+        @Override
+        public InputConfigurationCompat getInputConfiguration() {
+            return InputConfigurationCompat.wrap(mObject.getInputConfiguration());
+        }
+
+        @Override
+        public void setInputConfiguration(@NonNull InputConfigurationCompat input) {
+            mObject.setInputConfiguration((InputConfiguration) input.unwrap());
+        }
+
+        @Override
+        public CaptureRequest getSessionParameters() {
+            return mObject.getSessionParameters();
+        }
+
+        @Override
+        public void setSessionParameters(CaptureRequest params) {
+            mObject.setSessionParameters(params);
+        }
+
+        @Nullable
+        @Override
+        public Object getSessionConfiguration() {
+            return mObject;
+        }
+
+        @Override
+        public boolean equals(@Nullable Object obj) {
+            if (!(obj instanceof SessionConfigurationCompatApi28Impl)) {
+                return false;
+            }
+
+            return Objects.equals(mObject, ((SessionConfigurationCompatApi28Impl) obj).mObject);
+        }
+
+        @Override
+        public int hashCode() {
+            return mObject.hashCode();
+        }
+    }
+}
diff --git a/camera/camera2/src/test/java/androidx/camera/camera2/impl/compat/params/InputConfigurationCompatTest.java b/camera/camera2/src/test/java/androidx/camera/camera2/impl/compat/params/InputConfigurationCompatTest.java
index 3470302..6c421e4 100644
--- a/camera/camera2/src/test/java/androidx/camera/camera2/impl/compat/params/InputConfigurationCompatTest.java
+++ b/camera/camera2/src/test/java/androidx/camera/camera2/impl/compat/params/InputConfigurationCompatTest.java
@@ -34,7 +34,7 @@
 @RunWith(RobolectricTestRunner.class)
 @DoNotInstrument
 @Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
-public class InputConfigurationCompatTest {
+public final class InputConfigurationCompatTest {
 
     private static final int WIDTH = 1024;
     private static final int HEIGHT = 768;
diff --git a/camera/camera2/src/test/java/androidx/camera/camera2/impl/compat/params/SessionConfigurationCompatTest.java b/camera/camera2/src/test/java/androidx/camera/camera2/impl/compat/params/SessionConfigurationCompatTest.java
new file mode 100644
index 0000000..e122ef4
--- /dev/null
+++ b/camera/camera2/src/test/java/androidx/camera/camera2/impl/compat/params/SessionConfigurationCompatTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2019 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.camera.camera2.impl.compat.params;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.SessionConfiguration;
+import android.os.Build;
+import android.view.Surface;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+@SmallTest
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+public final class SessionConfigurationCompatTest {
+
+    private static final int WIDTH = 1024;
+    private static final int HEIGHT = 768;
+    private static final int FORMAT = ImageFormat.YUV_420_888;
+    private static final int DEFAULT_SESSION_TYPE = SessionConfigurationCompat.SESSION_REGULAR;
+
+    private List<OutputConfigurationCompat> mOutputs;
+    private Executor mCallbackExecutor;
+    private CameraCaptureSession.StateCallback mStateCallback;
+
+    @Before
+    public void setUp() {
+        mOutputs = new ArrayList<>();
+        for (int i = 0; i < 3; ++i) {
+            Surface surface = mock(Surface.class);
+            OutputConfigurationCompat outputConfigCompat = new OutputConfigurationCompat(surface);
+            mOutputs.add(outputConfigCompat);
+        }
+
+        mCallbackExecutor = mock(Executor.class);
+
+        mStateCallback = mock(CameraCaptureSession.StateCallback.class);
+    }
+
+    private SessionConfigurationCompat createDefaultSessionConfig() {
+        return new SessionConfigurationCompat(
+                DEFAULT_SESSION_TYPE,
+                mOutputs,
+                mCallbackExecutor,
+                mStateCallback);
+    }
+
+    @Test
+    public void canCreateSessionConfiguration() {
+        SessionConfigurationCompat sessionConfigCompat = createDefaultSessionConfig();
+
+        assertThat(sessionConfigCompat.getSessionType()).isEqualTo(DEFAULT_SESSION_TYPE);
+        assertThat(sessionConfigCompat.getOutputConfigurations()).containsExactlyElementsIn(
+                mOutputs);
+        assertThat(sessionConfigCompat.getExecutor()).isSameInstanceAs(mCallbackExecutor);
+        assertThat(sessionConfigCompat.getStateCallback()).isSameInstanceAs(mStateCallback);
+    }
+
+    @Test
+    @Config(minSdk = 28)
+    public void canWrapAndUnwrapSessionConfiguration() {
+        List<OutputConfiguration> outputConfigs = new ArrayList<>(mOutputs.size());
+        for (OutputConfigurationCompat outputConfigCompat : mOutputs) {
+            outputConfigs.add((OutputConfiguration) outputConfigCompat.unwrap());
+        }
+
+        SessionConfiguration sessionConfig = new SessionConfiguration(
+                SessionConfiguration.SESSION_REGULAR,
+                outputConfigs,
+                mCallbackExecutor,
+                mStateCallback);
+
+        SessionConfigurationCompat sessionConfigCompat = SessionConfigurationCompat.wrap(
+                sessionConfig);
+
+        assertThat(sessionConfigCompat.getSessionType()).isEqualTo(
+                SessionConfigurationCompat.SESSION_REGULAR);
+        assertThat(sessionConfigCompat.getOutputConfigurations()).containsExactlyElementsIn(
+                mOutputs);
+        assertThat(sessionConfigCompat.getExecutor()).isSameInstanceAs(mCallbackExecutor);
+        assertThat(sessionConfigCompat.getStateCallback()).isSameInstanceAs(mStateCallback);
+
+        assertThat(sessionConfigCompat.unwrap()).isSameInstanceAs(sessionConfig);
+        assertThat(
+                ((SessionConfiguration) sessionConfigCompat.unwrap()).getOutputConfigurations())
+                .containsExactlyElementsIn(
+                outputConfigs);
+    }
+
+    @Test
+    public void canSetAndRetrieveInputConfiguration() {
+        SessionConfigurationCompat sessionConfigCompat = createDefaultSessionConfig();
+
+        InputConfigurationCompat inputConfigurationCompat = new InputConfigurationCompat(WIDTH,
+                HEIGHT, FORMAT);
+
+        sessionConfigCompat.setInputConfiguration(inputConfigurationCompat);
+
+        // getInputConfiguration() is not necessarily the same instance, but should be equivalent
+        // by comparison
+        assertThat(sessionConfigCompat.getInputConfiguration()).isEqualTo(inputConfigurationCompat);
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void cannotSetInputConfiguration_onHighSpeedSession() {
+        SessionConfigurationCompat sessionConfigCompat = new SessionConfigurationCompat(
+                SessionConfigurationCompat.SESSION_HIGH_SPEED,
+                mOutputs,
+                mCallbackExecutor,
+                mStateCallback);
+
+        InputConfigurationCompat inputConfigurationCompat = new InputConfigurationCompat(WIDTH,
+                HEIGHT, FORMAT);
+
+        sessionConfigCompat.setInputConfiguration(inputConfigurationCompat);
+    }
+
+    @Test
+    @Config(minSdk = 28)
+    public void constantsMatchNonCompatVersion() {
+        assertThat(SessionConfigurationCompat.SESSION_REGULAR).isEqualTo(
+                SessionConfiguration.SESSION_REGULAR);
+        assertThat(SessionConfigurationCompat.SESSION_HIGH_SPEED).isEqualTo(
+                SessionConfiguration.SESSION_HIGH_SPEED);
+    }
+}
diff --git a/media2/player/src/androidTest/java/androidx/media2/player/MediaPlayerTest.java b/media2/player/src/androidTest/java/androidx/media2/player/MediaPlayerTest.java
index 89e2ebc..de69fc9 100644
--- a/media2/player/src/androidTest/java/androidx/media2/player/MediaPlayerTest.java
+++ b/media2/player/src/androidTest/java/androidx/media2/player/MediaPlayerTest.java
@@ -25,6 +25,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -1133,6 +1134,23 @@
     @Test
     @LargeTest
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
+    public void testSetPlaybackSpeedWithIllegalArguments() throws Throwable {
+        // Zero is not allowed.
+        ListenableFuture<PlayerResult> future = mPlayer.setPlaybackSpeed(0.0f);
+        PlayerResult result = future.get();
+        assertNotNull(result);
+        assertEquals(RESULT_ERROR_BAD_VALUE, result.getResultCode());
+
+        // Negative values are not allowed.
+        future = mPlayer.setPlaybackSpeed(-1.0f);
+        result = future.get();
+        assertNotNull(result);
+        assertEquals(RESULT_ERROR_BAD_VALUE, result.getResultCode());
+    }
+
+    @Test
+    @LargeTest
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
     public void testClose() throws Exception {
         assertTrue(loadResource(R.raw.testmp3_2));
         AudioAttributesCompat attributes = new AudioAttributesCompat.Builder()
diff --git a/media2/player/src/main/java/androidx/media2/player/MediaPlayer.java b/media2/player/src/main/java/androidx/media2/player/MediaPlayer.java
index de7cc0a..20ac028 100644
--- a/media2/player/src/main/java/androidx/media2/player/MediaPlayer.java
+++ b/media2/player/src/main/java/androidx/media2/player/MediaPlayer.java
@@ -823,6 +823,9 @@
         PendingFuture<PlayerResult> pendingFuture = new PendingFuture<PlayerResult>(mExecutor) {
             @Override
             List<ResolvableFuture<PlayerResult>> onExecute() {
+                if (playbackSpeed <= 0.0f) {
+                    return createFuturesForResultCode(RESULT_ERROR_BAD_VALUE);
+                }
                 ArrayList<ResolvableFuture<PlayerResult>> futures = new ArrayList<>();
                 ResolvableFuture<PlayerResult> future = ResolvableFuture.create();
                 synchronized (mPendingCommands) {
diff --git a/transition/src/main/java/androidx/transition/Transition.java b/transition/src/main/java/androidx/transition/Transition.java
index 7fe90fe..21895ca 100644
--- a/transition/src/main/java/androidx/transition/Transition.java
+++ b/transition/src/main/java/androidx/transition/Transition.java
@@ -1987,16 +1987,21 @@
      */
     @RestrictTo(LIBRARY_GROUP_PREFIX)
     void forceToEnd(ViewGroup sceneRoot) {
-        ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
+        final ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
         int numOldAnims = runningAnimators.size();
-        if (sceneRoot != null) {
-            WindowIdImpl windowId = ViewUtils.getWindowId(sceneRoot);
-            for (int i = numOldAnims - 1; i >= 0; i--) {
-                AnimationInfo info = runningAnimators.valueAt(i);
-                if (info.mView != null && windowId != null && windowId.equals(info.mWindowId)) {
-                    Animator anim = runningAnimators.keyAt(i);
-                    anim.end();
-                }
+        if (sceneRoot == null || numOldAnims == 0) {
+            return;
+        }
+
+        WindowIdImpl windowId = ViewUtils.getWindowId(sceneRoot);
+        final ArrayMap<Animator, AnimationInfo> oldAnimators = new ArrayMap(runningAnimators);
+        runningAnimators.clear();
+
+        for (int i = numOldAnims - 1; i >= 0; i--) {
+            AnimationInfo info = oldAnimators.valueAt(i);
+            if (info.mView != null && windowId != null && windowId.equals(info.mWindowId)) {
+                Animator anim = oldAnimators.keyAt(i);
+                anim.end();
             }
         }
     }
diff --git a/ui/animation/src/main/java/androidx/ui/animation/Transition.kt b/ui/animation/src/main/java/androidx/ui/animation/Transition.kt
index 61aa6e3..c1a49d5 100644
--- a/ui/animation/src/main/java/androidx/ui/animation/Transition.kt
+++ b/ui/animation/src/main/java/androidx/ui/animation/Transition.kt
@@ -49,7 +49,8 @@
     @Children children: @Composable() (state: TransitionState) -> Unit
 ) {
     if (transitionsEnabled) {
-        val model = +memo(definition) { TransitionModel(definition) }
+        // TODO: This null is workaround for b/132148894
+        val model = +memo(definition, null) { TransitionModel(definition) }
         model.anim.toState(toState)
         children(state = model)
     } else {
diff --git a/ui/material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/SelectionsControlsDemo.kt b/ui/material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/SelectionsControlsDemo.kt
index b6d6542..886dee2 100644
--- a/ui/material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/SelectionsControlsDemo.kt
+++ b/ui/material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/SelectionsControlsDemo.kt
@@ -33,6 +33,7 @@
 import androidx.ui.material.RadioGroup
 import androidx.ui.material.Switch
 import androidx.ui.material.parentCheckboxState
+import androidx.ui.material.surface.Surface
 import androidx.ui.material.themeTextStyle
 import androidx.ui.painting.Color
 import androidx.compose.Composable
@@ -58,27 +59,29 @@
     val headerStyle = +themeTextStyle { h6 }
     val padding = EdgeInsets(10.dp)
 
-    Padding(padding = padding) {
-        Column(crossAxisAlignment = CrossAxisAlignment.Start) {
-            Text(text = "Checkbox", style = headerStyle)
-            Padding(padding = padding) {
-                CheckboxDemo()
-            }
-            Text(text = "Switch", style = headerStyle)
-            Padding(padding = padding) {
-                SwitchDemo()
-            }
-            Text(text = "RadioButton", style = headerStyle)
-            Padding(padding = padding) {
-                RadioButtonDemo()
-            }
-            Text(text = "Radio group :: Default usage", style = headerStyle)
-            Padding(padding = padding) {
-                DefaultRadioGroup()
-            }
-            Text(text = "Radio group :: Custom usage", style = headerStyle)
-            Padding(padding = padding) {
-                CustomRadioGroup()
+    Surface {
+        Padding(padding = padding) {
+            Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+                Text(text = "Checkbox", style = headerStyle)
+                Padding(padding = padding) {
+                    CheckboxDemo()
+                }
+                Text(text = "Switch", style = headerStyle)
+                Padding(padding = padding) {
+                    SwitchDemo()
+                }
+                Text(text = "RadioButton", style = headerStyle)
+                Padding(padding = padding) {
+                    RadioButtonDemo()
+                }
+                Text(text = "Radio group :: Default usage", style = headerStyle)
+                Padding(padding = padding) {
+                    DefaultRadioGroup()
+                }
+                Text(text = "Radio group :: Custom usage", style = headerStyle)
+                Padding(padding = padding) {
+                    CustomRadioGroup()
+                }
             }
         }
     }
diff --git a/ui/material/src/androidTest/java/androidx/ui/material/CheckboxUiTest.kt b/ui/material/src/androidTest/java/androidx/ui/material/CheckboxUiTest.kt
index 44d72b7..09b449e 100644
--- a/ui/material/src/androidTest/java/androidx/ui/material/CheckboxUiTest.kt
+++ b/ui/material/src/androidTest/java/androidx/ui/material/CheckboxUiTest.kt
@@ -40,6 +40,7 @@
 import com.google.common.truth.Truth
 import androidx.compose.Model
 import androidx.compose.composer
+import androidx.ui.core.round
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -107,10 +108,10 @@
         setMaterialContent {
             TestTag(tag = defaultTag) {
                 Checkbox(
-                        value = state.value,
-                        onClick = {
-                            state.toggle()
-                        })
+                    value = state.value,
+                    onClick = {
+                        state.toggle()
+                    })
             }
         }
 
@@ -127,10 +128,10 @@
         setMaterialContent {
             TestTag(tag = defaultTag) {
                 Checkbox(
-                        value = state.value,
-                        onClick = {
-                            state.toggle()
-                        })
+                    value = state.value,
+                    onClick = {
+                        state.toggle()
+                    })
             }
         }
 
@@ -186,8 +187,9 @@
             }
         }
         withDensity(density) {
-            Truth.assertThat(checkboxSize?.width).isEqualTo(materialCheckboxSize.toPx())
-            Truth.assertThat(checkboxSize?.height).isEqualTo(materialCheckboxSize.toPx())
+            Truth.assertThat(checkboxSize?.width?.round()).isEqualTo(materialCheckboxSize.toIntPx())
+            Truth.assertThat(checkboxSize?.height?.round())
+                .isEqualTo(materialCheckboxSize.toIntPx())
         }
     }
 }
\ No newline at end of file
diff --git a/ui/material/src/androidTest/java/androidx/ui/material/MaterialTest.kt b/ui/material/src/androidTest/java/androidx/ui/material/MaterialTest.kt
index 216dbb2..ddae1d0 100644
--- a/ui/material/src/androidTest/java/androidx/ui/material/MaterialTest.kt
+++ b/ui/material/src/androidTest/java/androidx/ui/material/MaterialTest.kt
@@ -18,12 +18,15 @@
 
 import androidx.compose.Composable
 import androidx.compose.composer
+import androidx.ui.material.surface.Surface
 import androidx.ui.test.android.AndroidUiTestRunner
 
 fun AndroidUiTestRunner.setMaterialContent(composable: @Composable() () -> Unit) {
     setContent {
         MaterialTheme {
-            composable()
+            Surface {
+                composable()
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/ui/material/src/androidTest/java/androidx/ui/material/RadioGroupUiTest.kt b/ui/material/src/androidTest/java/androidx/ui/material/RadioGroupUiTest.kt
index bfafb67..09428f5 100644
--- a/ui/material/src/androidTest/java/androidx/ui/material/RadioGroupUiTest.kt
+++ b/ui/material/src/androidTest/java/androidx/ui/material/RadioGroupUiTest.kt
@@ -17,8 +17,14 @@
 package androidx.ui.material
 
 import androidx.test.filters.MediumTest
+import androidx.ui.core.OnChildPositioned
+import androidx.ui.core.PxSize
 import androidx.ui.core.TestTag
+import androidx.ui.core.dp
+import androidx.ui.core.withDensity
 import androidx.ui.layout.Column
+import androidx.ui.layout.Container
+import androidx.ui.layout.DpConstraints
 import androidx.ui.test.android.AndroidUiTestRunner
 import androidx.ui.test.assertIsInMutuallyExclusiveGroup
 import androidx.ui.test.assertIsSelected
@@ -31,6 +37,8 @@
 import androidx.compose.Composable
 import androidx.compose.Model
 import androidx.compose.composer
+import androidx.ui.core.round
+import com.google.common.truth.Truth
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -46,6 +54,8 @@
     private val itemTwo = "Foo"
     private val itemThree = "Sap"
 
+    private val materialRadioSize = 24.dp
+
     private val unselectedRadioGroupItemSemantics = createFullSemantics(
         inMutuallyExclusiveGroup = true,
         isSelected = false
@@ -74,9 +84,9 @@
                 options.forEach { item ->
                     TestTag(tag = item) {
                         RadioGroupTextItem(
-                                text = item,
-                                selected = (select.selected == item),
-                                onSelected = { select.selected = item })
+                            text = item,
+                            selected = (select.selected == item),
+                            onSelected = { select.selected = item })
                     }
                 }
             }
@@ -106,9 +116,9 @@
                 options.forEach { item ->
                     TestTag(tag = item) {
                         RadioGroupTextItem(
-                                text = item,
-                                selected = (select.selected == item),
-                                onSelected = { select.selected = item })
+                            text = item,
+                            selected = (select.selected == item),
+                            onSelected = { select.selected = item })
                     }
                 }
             }
@@ -134,9 +144,9 @@
                 options.forEach { item ->
                     TestTag(tag = item) {
                         RadioGroupTextItem(
-                                text = item,
-                                selected = (select.selected == item),
-                                onSelected = { select.selected = item })
+                            text = item,
+                            selected = (select.selected == item),
+                            onSelected = { select.selected = item })
                     }
                 }
             }
@@ -162,9 +172,9 @@
                 options.forEach { item ->
                     TestTag(tag = item) {
                         RadioGroupTextItem(
-                                text = item,
-                                selected = (select.selected == item),
-                                onSelected = { select.selected = item })
+                            text = item,
+                            selected = (select.selected == item),
+                            onSelected = { select.selected = item })
                     }
                 }
             }
@@ -189,4 +199,36 @@
         findByTag(itemTwo)
             .assertSemanticsIsEqualTo(unselectedRadioGroupItemSemantics)
     }
+
+    @Test
+    fun radioButton_materialSizes_whenSelected() {
+        materialSizesTestForValue(selected = true)
+    }
+
+    @Test
+    fun radioButton_materialSizes_whenNotSelected() {
+        materialSizesTestForValue(selected = false)
+    }
+
+    private fun materialSizesTestForValue(selected: Boolean) {
+        var radioSize: PxSize? = null
+        setMaterialContent {
+            Container(
+                constraints = DpConstraints(
+                    maxWidth = 5000.dp,
+                    maxHeight = 5000.dp
+                )
+            ) {
+                OnChildPositioned(onPositioned = { coordinates ->
+                    radioSize = coordinates.size
+                }) {
+                    RadioButton(selected = selected)
+                }
+            }
+        }
+        withDensity(density) {
+            Truth.assertThat(radioSize?.width?.round()).isEqualTo(materialRadioSize.toIntPx())
+            Truth.assertThat(radioSize?.height?.round()).isEqualTo(materialRadioSize.toIntPx())
+        }
+    }
 }
\ No newline at end of file
diff --git a/ui/material/src/androidTest/java/androidx/ui/material/SwitchUiTest.kt b/ui/material/src/androidTest/java/androidx/ui/material/SwitchUiTest.kt
index 94869bf..85a49fb 100644
--- a/ui/material/src/androidTest/java/androidx/ui/material/SwitchUiTest.kt
+++ b/ui/material/src/androidTest/java/androidx/ui/material/SwitchUiTest.kt
@@ -17,8 +17,15 @@
 package androidx.ui.material
 
 import androidx.test.filters.MediumTest
+
+import androidx.ui.core.OnChildPositioned
+import androidx.ui.core.PxSize
 import androidx.ui.core.TestTag
+import androidx.ui.core.dp
+import androidx.ui.core.withDensity
 import androidx.ui.layout.Column
+import androidx.ui.layout.Container
+import androidx.ui.layout.DpConstraints
 import androidx.ui.test.DisableTransitions
 import androidx.ui.test.android.AndroidUiTestRunner
 import androidx.ui.test.assertIsChecked
@@ -30,7 +37,8 @@
 import androidx.ui.test.findByTag
 import androidx.compose.state
 import androidx.compose.unaryPlus
-import androidx.compose.composer
+import androidx.ui.core.round
+import com.google.common.truth.Truth
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -53,7 +61,7 @@
     private val defaultSwitchTag = "switch"
 
     @Test
-    fun SwitchTest_defaultSemantics() {
+    fun switch_defaultSemantics() {
         setMaterialContent {
             Column {
                 TestTag(tag = "checked") {
@@ -70,7 +78,7 @@
     }
 
     @Test
-    fun SwitchTest_toggle() {
+    fun switch_toggle() {
         setMaterialContent {
             val (checked, onChecked) = +state { false }
             TestTag(tag = defaultSwitchTag) {
@@ -84,12 +92,12 @@
     }
 
     @Test
-    fun SwitchTest_toggleTwice() {
+    fun switch_toggleTwice() {
 
         setMaterialContent {
             val (checked, onChecked) = +state { false }
             TestTag(tag = defaultSwitchTag) {
-                Switch(checked = checked, onClick = { onChecked(!checked)})
+                Switch(checked = checked, onClick = { onChecked(!checked) })
             }
         }
         findByTag(defaultSwitchTag)
@@ -101,7 +109,7 @@
     }
 
     @Test
-    fun SwitchTest_uncheckableWithNoLambda() {
+    fun switch_uncheckableWithNoLambda() {
         setMaterialContent {
             val (checked, _) = +state { false }
             TestTag(tag = defaultSwitchTag) {
@@ -113,4 +121,38 @@
             .doClick()
             .assertIsNotChecked()
     }
+
+    @Test
+    fun switch_materialSizes_whenChecked() {
+        materialSizesTestForValue(true)
+    }
+
+    @Test
+    fun switch_materialSizes_whenUnchecked() {
+        materialSizesTestForValue(false)
+    }
+
+    private fun materialSizesTestForValue(checked: Boolean) {
+        var switchSize: PxSize? = null
+        setMaterialContent {
+            Container(
+                constraints = DpConstraints(
+                    maxWidth = 5000.dp,
+                    maxHeight = 5000.dp
+                )
+            ) {
+                OnChildPositioned(onPositioned = { coordinates ->
+                    switchSize = coordinates.size
+                }) {
+                    Switch(checked = checked)
+                }
+            }
+        }
+        withDensity(density) {
+            Truth.assertThat(switchSize?.width?.round())
+                .isEqualTo(34.dp.toIntPx() + 2.dp.toIntPx() * 2)
+            Truth.assertThat(switchSize?.height?.round())
+                .isEqualTo(20.dp.toIntPx() + 2.dp.toIntPx() * 2)
+        }
+    }
 }
\ No newline at end of file
diff --git a/ui/material/src/main/java/androidx/ui/baseui/Clickable.kt b/ui/material/src/main/java/androidx/ui/baseui/Clickable.kt
index 362f1e1..acfec85 100644
--- a/ui/material/src/main/java/androidx/ui/baseui/Clickable.kt
+++ b/ui/material/src/main/java/androidx/ui/baseui/Clickable.kt
@@ -41,18 +41,20 @@
     @Children children: @Composable() () -> Unit
 ) {
     Semantics(
-        button=true,
-        enabled=(onClick != null),
-        actions=if (onClick != null) {
+        button = true,
+        enabled = (onClick != null),
+        actions = if (onClick != null) {
             // TODO(ryanmentley): The unnecessary generic type specification works around an IR bug
             listOf<SemanticsAction<*>>(SemanticsAction(SemanticsActionType.Tap, onClick))
         } else {
             emptyList<SemanticsAction<*>>()
-        }) {
+        }
+    ) {
         PressReleasedGestureDetector(
             onRelease = onClick,
-            consumeDownOnStart = consumeDownOnStart) {
+            consumeDownOnStart = consumeDownOnStart
+        ) {
             children()
         }
     }
-}
+}
\ No newline at end of file
diff --git a/ui/material/src/main/java/androidx/ui/baseui/selection/MutuallyExclusiveSetItem.kt b/ui/material/src/main/java/androidx/ui/baseui/selection/MutuallyExclusiveSetItem.kt
index 704a64a..c9ca5d8 100644
--- a/ui/material/src/main/java/androidx/ui/baseui/selection/MutuallyExclusiveSetItem.kt
+++ b/ui/material/src/main/java/androidx/ui/baseui/selection/MutuallyExclusiveSetItem.kt
@@ -16,11 +16,11 @@
 
 package androidx.ui.baseui.selection
 
-import androidx.ui.core.gesture.PressGestureDetector
-import androidx.ui.core.Semantics
 import androidx.compose.Children
 import androidx.compose.Composable
 import androidx.compose.composer
+import androidx.ui.core.Semantics
+import androidx.ui.core.gesture.PressReleasedGestureDetector
 
 /**
  * Component for representing one option out of many
@@ -37,10 +37,14 @@
     onSelected: () -> Unit,
     @Children children: @Composable() () -> Unit
 ) {
-    PressGestureDetector(onPress = { onSelected() }) {
+    PressReleasedGestureDetector(
+        onRelease = onSelected,
+        consumeDownOnStart = false
+    ) {
         Semantics(
             inMutuallyExclusiveGroup = true,
-            selected = selected) {
+            selected = selected
+        ) {
             children()
         }
     }
diff --git a/ui/material/src/main/java/androidx/ui/baseui/selection/Toggleable.kt b/ui/material/src/main/java/androidx/ui/baseui/selection/Toggleable.kt
index bf1cdc8..a4957c8 100644
--- a/ui/material/src/main/java/androidx/ui/baseui/selection/Toggleable.kt
+++ b/ui/material/src/main/java/androidx/ui/baseui/selection/Toggleable.kt
@@ -17,7 +17,7 @@
 package androidx.ui.baseui.selection
 
 import androidx.ui.core.Semantics
-import androidx.ui.core.gesture.PressGestureDetector
+import androidx.ui.core.gesture.PressReleasedGestureDetector
 import androidx.ui.core.semantics.SemanticsAction
 import androidx.ui.core.semantics.SemanticsActionType
 import androidx.compose.Children
@@ -35,8 +35,9 @@
     } else {
         emptyList()
     }
-    // TODO should we use PressReleasedGestureDetector?
-    PressGestureDetector(onRelease = onToggle) {
+    PressReleasedGestureDetector(
+        onRelease = onToggle,
+        consumeDownOnStart = false) {
         // TODO: enabled should not be hardcoded
         // TODO(pavlis): Semantics currently doesn't support 4 states (only checked / unchecked / not checkable).
         Semantics(
diff --git a/ui/material/src/main/java/androidx/ui/material/Checkbox.kt b/ui/material/src/main/java/androidx/ui/material/Checkbox.kt
index f8308a3..a8b63e4 100644
--- a/ui/material/src/main/java/androidx/ui/material/Checkbox.kt
+++ b/ui/material/src/main/java/androidx/ui/material/Checkbox.kt
@@ -24,14 +24,13 @@
 import androidx.ui.baseui.selection.Toggleable
 import androidx.ui.baseui.selection.ToggleableState
 import androidx.ui.core.Draw
-import androidx.ui.core.Layout
-import androidx.ui.core.coerceIn
 import androidx.ui.core.dp
 import androidx.ui.engine.geometry.Offset
 import androidx.ui.engine.geometry.RRect
 import androidx.ui.engine.geometry.Radius
 import androidx.ui.engine.geometry.shrink
 import androidx.ui.engine.geometry.withRadius
+import androidx.ui.layout.Container
 import androidx.ui.layout.Padding
 import androidx.ui.painting.Color
 import androidx.ui.painting.Paint
@@ -41,6 +40,8 @@
 import androidx.compose.composer
 import androidx.compose.memo
 import androidx.compose.unaryPlus
+import androidx.ui.layout.Wrap
+import androidx.ui.material.ripple.Ripple
 
 // TODO(malkov): think about how to abstract it better
 /**
@@ -73,16 +74,15 @@
     onClick: (() -> Unit)? = null,
     color: Color? = null
 ) {
-    Toggleable(value = value, onToggle = onClick) {
-        Padding(padding = CheckboxDefaultPadding) {
-            Layout(
-                children = { DrawCheckbox(value = value, color = color) },
-                layoutBlock = { _, constraints ->
-                val checkboxSizePx = CheckboxSize.toIntPx()
-                val height = checkboxSizePx.coerceIn(constraints.minHeight, constraints.maxHeight)
-                val width = checkboxSizePx.coerceIn(constraints.minWidth, constraints.maxWidth)
-                layout(width, height) {}
-            })
+    Wrap {
+        Ripple {
+            Toggleable(value = value, onToggle = onClick) {
+                Padding(padding = CheckboxDefaultPadding) {
+                    Container(width = CheckboxSize, height = CheckboxSize) {
+                        DrawCheckbox(value = value, color = color)
+                    }
+                }
+            }
         }
     }
 }
@@ -90,29 +90,32 @@
 @Composable
 private fun DrawCheckbox(value: ToggleableState, color: Color?) {
     val activeColor = +color.orFromTheme { secondary }
-    val definition = +memo(activeColor) {
-        generateTransitionDefinition(activeColor)
+    val unselectedColor = (+themeColor { onSurface }).withOpacity(UncheckedBoxOppacity)
+    val definition = +memo(activeColor, unselectedColor) {
+        generateTransitionDefinition(activeColor, unselectedColor)
     }
     // TODO: remove @Composable annotation here when b/131681875 is fixed
     Transition(definition = definition, toState = value) @Composable { state ->
         DrawBox(
             color = state[BoxColorProp],
-            innerRadiusFraction = state[InnerRadiusFractionProp])
+            innerRadiusFraction = state[InnerRadiusFractionProp]
+        )
         DrawCheck(
             checkFraction = state[CheckFractionProp],
-            crossCenterGravitation = state[CenterGravitationForCheck])
+            crossCenterGravitation = state[CenterGravitationForCheck]
+        )
     }
 }
 
 @Composable
 private fun DrawBox(color: Color, innerRadiusFraction: Float) {
-    Draw { canvas, _ ->
+    Draw { canvas, parentSize ->
         val paint = Paint()
         paint.strokeWidth = StrokeWidth.toPx().value
         paint.isAntiAlias = true
         paint.color = color
 
-        val checkboxSize = CheckboxSize.toPx().value
+        val checkboxSize = parentSize.width.value
 
         val outer = RRect(
             0f,
@@ -142,7 +145,7 @@
     checkFraction: Float,
     crossCenterGravitation: Float
 ) {
-    Draw { canvas, _ ->
+    Draw { canvas, parentSize ->
         val paint = Paint()
         paint.isAntiAlias = true
         paint.style = PaintingStyle.stroke
@@ -150,7 +153,7 @@
         paint.strokeWidth = StrokeWidth.toPx().value
         paint.color = CheckStrokeDefaultColor
 
-        val width = CheckboxSize.toPx().value
+        val width = parentSize.width.value
 
         val checkCrossX = 0.4f
         val checkCrossY = 0.7f
@@ -193,54 +196,55 @@
 private val BoxAnimationDuration = 100
 private val CheckStrokeAnimationDuration = 100
 
-private fun generateTransitionDefinition(color: Color) = transitionDefinition {
-    state(ToggleableState.Checked) {
-        this[CheckFractionProp] = 1f
-        this[InnerRadiusFractionProp] = 1f
-        this[CenterGravitationForCheck] = 0f
-        this[BoxColorProp] = color
-    }
-    state(ToggleableState.Unchecked) {
-        this[CheckFractionProp] = 0f
-        this[InnerRadiusFractionProp] = 0f
-        this[CenterGravitationForCheck] = 1f
-        this[BoxColorProp] = UncheckedBoxColor
-    }
-    state(ToggleableState.Indeterminate) {
-        this[CheckFractionProp] = 1f
-        this[InnerRadiusFractionProp] = 1f
-        this[CenterGravitationForCheck] = 1f
-        this[BoxColorProp] = color
-    }
-    transition(fromState = ToggleableState.Unchecked, toState = ToggleableState.Checked) {
-        boxTransitionFromUnchecked()
-        CenterGravitationForCheck using tween {
-            duration = 0
+private fun generateTransitionDefinition(color: Color, unselectedColor: Color) =
+    transitionDefinition {
+        state(ToggleableState.Checked) {
+            this[CheckFractionProp] = 1f
+            this[InnerRadiusFractionProp] = 1f
+            this[CenterGravitationForCheck] = 0f
+            this[BoxColorProp] = color
+        }
+        state(ToggleableState.Unchecked) {
+            this[CheckFractionProp] = 0f
+            this[InnerRadiusFractionProp] = 0f
+            this[CenterGravitationForCheck] = 1f
+            this[BoxColorProp] = unselectedColor
+        }
+        state(ToggleableState.Indeterminate) {
+            this[CheckFractionProp] = 1f
+            this[InnerRadiusFractionProp] = 1f
+            this[CenterGravitationForCheck] = 1f
+            this[BoxColorProp] = color
+        }
+        transition(fromState = ToggleableState.Unchecked, toState = ToggleableState.Checked) {
+            boxTransitionFromUnchecked()
+            CenterGravitationForCheck using tween {
+                duration = 0
+            }
+        }
+        transition(fromState = ToggleableState.Checked, toState = ToggleableState.Unchecked) {
+            boxTransitionToUnchecked()
+            CenterGravitationForCheck using tween {
+                duration = CheckStrokeAnimationDuration
+            }
+        }
+        transition(fromState = ToggleableState.Checked, toState = ToggleableState.Indeterminate) {
+            CenterGravitationForCheck using tween {
+                duration = CheckStrokeAnimationDuration
+            }
+        }
+        transition(fromState = ToggleableState.Indeterminate, toState = ToggleableState.Checked) {
+            CenterGravitationForCheck using tween {
+                duration = CheckStrokeAnimationDuration
+            }
+        }
+        transition(fromState = ToggleableState.Indeterminate, toState = ToggleableState.Unchecked) {
+            boxTransitionToUnchecked()
+        }
+        transition(fromState = ToggleableState.Unchecked, toState = ToggleableState.Indeterminate) {
+            boxTransitionFromUnchecked()
         }
     }
-    transition(fromState = ToggleableState.Checked, toState = ToggleableState.Unchecked) {
-        boxTransitionToUnchecked()
-        CenterGravitationForCheck using tween {
-            duration = CheckStrokeAnimationDuration
-        }
-    }
-    transition(fromState = ToggleableState.Checked, toState = ToggleableState.Indeterminate) {
-        CenterGravitationForCheck using tween {
-            duration = CheckStrokeAnimationDuration
-        }
-    }
-    transition(fromState = ToggleableState.Indeterminate, toState = ToggleableState.Checked) {
-        CenterGravitationForCheck using tween {
-            duration = CheckStrokeAnimationDuration
-        }
-    }
-    transition(fromState = ToggleableState.Indeterminate, toState = ToggleableState.Unchecked) {
-        boxTransitionToUnchecked()
-    }
-    transition(fromState = ToggleableState.Unchecked, toState = ToggleableState.Indeterminate) {
-        boxTransitionFromUnchecked()
-    }
-}
 
 private fun TransitionSpec.boxTransitionFromUnchecked() {
     BoxColorProp using tween {
@@ -273,5 +277,5 @@
 private val StrokeWidth = 2.dp
 private val RadiusSize = 2.dp
 
-private val UncheckedBoxColor = Color(0xFF7D7D7D.toInt())
+private val UncheckedBoxOppacity = 0.6f
 private val CheckStrokeDefaultColor = Color(0xFFFFFFFF.toInt())
\ No newline at end of file
diff --git a/ui/material/src/main/java/androidx/ui/material/RadioButton.kt b/ui/material/src/main/java/androidx/ui/material/RadioButton.kt
index b1a87aa..e51952d 100644
--- a/ui/material/src/main/java/androidx/ui/material/RadioButton.kt
+++ b/ui/material/src/main/java/androidx/ui/material/RadioButton.kt
@@ -24,19 +24,16 @@
 import androidx.ui.core.DensityReceiver
 import androidx.ui.core.Dp
 import androidx.ui.core.Draw
-import androidx.ui.core.Layout
-import androidx.ui.core.Layout
 import androidx.ui.core.PxSize
 import androidx.ui.core.Text
 import androidx.ui.core.dp
-import androidx.ui.core.max
-import androidx.ui.core.min
 import androidx.ui.engine.geometry.Offset
 import androidx.ui.engine.geometry.RRect
 import androidx.ui.engine.geometry.Radius
 import androidx.ui.engine.geometry.shift
 import androidx.ui.engine.geometry.shrink
 import androidx.ui.layout.Column
+import androidx.ui.layout.Container
 import androidx.ui.layout.EdgeInsets
 import androidx.ui.layout.MainAxisAlignment
 import androidx.ui.layout.MainAxisSize
@@ -52,6 +49,7 @@
 import androidx.compose.composer
 import androidx.compose.memo
 import androidx.compose.unaryPlus
+import androidx.ui.material.ripple.BoundedRipple
 
 /**
  * Components for creating mutually exclusive set of [RadioButton]s.
@@ -142,10 +140,14 @@
         onSelected: () -> Unit,
         @Children children: @Composable() () -> Unit
     ) {
-        MutuallyExclusiveSetItem(
-            selected = selected,
-            onSelected = { if (!selected) onSelected() }) {
-            children()
+        Container {
+            BoundedRipple {
+                MutuallyExclusiveSetItem(
+                    selected = selected,
+                    onSelected = { if (!selected) onSelected() }) {
+                    children()
+                }
+            }
         }
     }
 
@@ -202,27 +204,24 @@
     selected: Boolean,
     color: Color? = null
 ) {
-    Layout(children = {
-        val activeColor = +color.orFromTheme { primary }
-        val definition = +memo(activeColor) {
-            generateTransitionDefinition(activeColor)
+    Padding(padding = RadioButtonPadding) {
+        Container(width = RadioButtonSize, height = RadioButtonSize) {
+            val selectedColor = +color.orFromTheme { secondary }
+            val unselectedColor = (+themeColor { onSurface }).withOpacity(UnselectedOpacity)
+            val definition = +memo(selectedColor, unselectedColor) {
+                generateTransitionDefinition(selectedColor, unselectedColor)
+            }
+            // TODO: remove @Composable annotation here when b/131681875 is fixed
+            Transition(definition = definition, toState = selected) @Composable { state ->
+                DrawRadioButton(
+                    color = state[ColorProp],
+                    outerRadius = state[OuterRadiusProp],
+                    innerRadius = state[InnerRadiusProp],
+                    gap = state[GapProp]
+                )
+            }
         }
-        // TODO: remove @Composable annotation here when b/131681875 is fixed
-        Transition(definition = definition, toState = selected) @Composable { state ->
-            DrawRadioButton(
-                color = state[ColorProp],
-                outerRadius = state[OuterRadiusProp],
-                innerRadius = state[InnerRadiusProp],
-                gap = state[GapProp])
-        }
-    }, layoutBlock = { _, constraints ->
-        val size = RadioRadius.toIntPx() * 2
-        val w = max(constraints.minWidth, min(constraints.maxWidth, size))
-        val h = max(constraints.minHeight, min(constraints.maxHeight, size))
-        layout(w, h) {
-            // no children to place
-        }
-    })
+    }
 }
 
 @Composable
@@ -282,18 +281,21 @@
 private val GapDuration = 150
 private val TotalDuration = RadiusClosureDuration + PulseDuration + GapDuration
 
-private fun generateTransitionDefinition(activeColor: Color) = transitionDefinition {
+private fun generateTransitionDefinition(
+    selectedColor: Color,
+    unselectedColor: Color
+) = transitionDefinition {
     state(false) {
         this[OuterRadiusProp] = RadioRadius
         this[InnerRadiusProp] = InitialInner
         this[GapProp] = 0.dp
-        this[ColorProp] = UnselectedRadioColor
+        this[ColorProp] = unselectedColor
     }
     state(true) {
         this[OuterRadiusProp] = RadioRadius
         this[InnerRadiusProp] = 0.dp
         this[GapProp] = DefaultGap
-        this[ColorProp] = activeColor
+        this[ColorProp] = selectedColor
     }
     transition(fromState = false, toState = true) {
         ColorProp using tween {
@@ -339,13 +341,13 @@
     }
 }
 
-// TODO(malkov): see how it goes and maybe move it to styles or cross-widget defaults
-private val UnselectedRadioColor = Color(0xFF7D7D7D.toInt())
-
-// TODO(malkov): random numbers for now to produce radio as in material comp.
-private val RadioRadius = 10.dp
+private val RadioButtonPadding = 2.dp
+private val RadioButtonSize = 20.dp
+private val RadioRadius = RadioButtonSize / 2
 private val RadioStrokeWidth = 2.dp
+// TODO(malkov): random numbers for now to produce radio as in material comp.
 private val DefaultGap = 3.dp
+private val UnselectedOpacity = 0.6f
 
 // for animations
 private val OuterOffsetDuringAnimation = 2.dp
diff --git a/ui/material/src/main/java/androidx/ui/material/Switch.kt b/ui/material/src/main/java/androidx/ui/material/Switch.kt
index 5ac0fc9..a5d48c7 100644
--- a/ui/material/src/main/java/androidx/ui/material/Switch.kt
+++ b/ui/material/src/main/java/androidx/ui/material/Switch.kt
@@ -17,21 +17,18 @@
 package androidx.ui.material
 
 import androidx.animation.ColorPropKey
+import androidx.animation.FastOutSlowInEasing
 import androidx.animation.FloatPropKey
 import androidx.animation.TransitionSpec
 import androidx.animation.transitionDefinition
 import androidx.ui.animation.Transition
 import androidx.ui.baseui.selection.Toggleable
 import androidx.ui.baseui.selection.ToggleableState
-import androidx.ui.core.Constraints
 import androidx.ui.core.DensityReceiver
 import androidx.ui.core.Draw
-import androidx.ui.core.Layout
-import androidx.ui.core.PxSize
-import androidx.ui.core.coerceIn
 import androidx.ui.core.dp
-import androidx.ui.core.ipx
 import androidx.ui.engine.geometry.Offset
+import androidx.ui.layout.Container
 import androidx.ui.painting.Canvas
 import androidx.ui.painting.Color
 import androidx.ui.painting.Paint
@@ -40,6 +37,10 @@
 import androidx.compose.composer
 import androidx.compose.memo
 import androidx.compose.unaryPlus
+import androidx.ui.core.PxSize
+import androidx.ui.layout.Padding
+import androidx.ui.layout.Wrap
+import androidx.ui.material.ripple.Ripple
 
 /**
  * A Switch is a two state toggleable component that provides on/off like options
@@ -48,7 +49,7 @@
  * @param onClick callback to be invoked when Switch is clicked.
  * if [null], Switch will show static [checked] state and remain disabled
  * @param color optional active color for Switch,
- * by default [androidx.ui.material.MaterialColors.primary] will be used
+ * by default [androidx.ui.material.MaterialColors.secondaryVariant] will be used
  */
 @Composable
 fun Switch(
@@ -57,34 +58,38 @@
     color: Color? = null
 ) {
     val value = if (checked) ToggleableState.Checked else ToggleableState.Unchecked
-    Toggleable(value = value, onToggle = onClick) {
-        val children = @Composable { DrawSwitch(checked = checked, color = color) }
-        Layout(children = children, layoutBlock = { measurables, constraints ->
-            val height =
-                MinHeight.toIntPx().coerceIn(constraints.minHeight, constraints.maxHeight)
-            val width =
-                MinWidth.toIntPx().coerceIn(constraints.minWidth, constraints.maxWidth)
-            val ps = measurables.map { m ->
-                m.measure(Constraints.tightConstraints(width, height))
+    Wrap {
+        Ripple {
+            Toggleable(value = value, onToggle = onClick) {
+                Padding(padding = DefaultSwitchPadding) {
+                    Container(width = SwitchWidth, height = SwitchHeight) {
+                        DrawSwitch(checked = checked, color = color)
+                    }
+                }
             }
-            layout(width, height) { ps.forEach { it.place(0.ipx, 0.ipx) } }
-        })
+        }
     }
 }
 
 @Composable
 private fun DrawSwitch(checked: Boolean, color: Color? = null) {
-    val activeColor = +color.orFromTheme { primary }
-    val transDef = +memo(activeColor) {
-        generateTransitionDefinition(activeColor)
+    val checkedThumbColor = +color.orFromTheme { secondaryVariant }
+    val uncheckedThumbColor = +themeColor { surface }
+    val transDef = +memo(checkedThumbColor, uncheckedThumbColor) {
+        generateTransitionDefinition(checkedThumbColor, uncheckedThumbColor)
     }
-    val trackColor = if (checked) activeColor else UncheckedTrackColor
+    val trackColor = if (checked) {
+        checkedThumbColor.withOpacity(CheckedTrackOpacity)
+    } else {
+        (+themeColor { onSurface }).withOpacity(UncheckedTrackOpacity)
+    }
     DrawTrack(color = trackColor)
     // TODO: remove @Composable annotation here when b/131681875 is fixed
     Transition(definition = transDef, toState = checked) @Composable { state ->
         DrawThumb(
             color = state[ThumbColorProp],
-            relativePosition = state[RelativeThumbTranslationProp])
+            relativePosition = state[RelativeThumbTranslationProp]
+        )
     }
 }
 
@@ -108,21 +113,19 @@
     color: Color
 ) {
     val paint = Paint()
-
     paint.isAntiAlias = true
     paint.color = color
-        .withAlpha(TrackAlpha)
     paint.strokeCap = StrokeCap.round
-    paint.strokeWidth = TrackHeight.toPx().value
+    paint.strokeWidth = TrackStrokeWidth.toPx().value
 
-    // TODO(malkov): currently Switch gravity is always CENTER but we need to be flexible
-    val centerHeight = parentSize.height.value / 2
-    val centerWidth = parentSize.width.value / 2
+    val strokeRadius = TrackStrokeWidth / 2
+    val centerHeight = parentSize.height / 2
 
-    val startW = centerWidth - TrackWidth.toPx().value / 2
-    val endW = centerWidth + TrackWidth.toPx().value / 2
-
-    canvas.drawLine(Offset(startW, centerHeight), Offset(endW, centerHeight), paint)
+    canvas.drawLine(
+        Offset(strokeRadius.toPx().value, centerHeight.value),
+        Offset((TrackWidth - strokeRadius).toPx().value, centerHeight.value),
+        paint
+    )
 }
 
 private fun DensityReceiver.drawThumb(
@@ -132,57 +135,60 @@
     color: Color
 ) {
     val paint = Paint()
-
     paint.isAntiAlias = true
     paint.color = color
 
-    // currently I assume that layout gravity of Switch is always CENTER
-    val centerHeight = parentSize.height.value / 2
-    val centerWidth = parentSize.width.value / 2
+    val centerHeight = parentSize.height / 2
+    val thumbRadius = ThumbDiameter / 2
+    val thumbPathWidth = TrackWidth - ThumbDiameter
 
-    val thumbTrackWidth = TrackWidth + PointRadius
-    val thumbStartPoint = centerWidth - thumbTrackWidth.toPx().value / 2
-
-    val start = thumbStartPoint + thumbTrackWidth.toPx().value * relativePosition
-    canvas.drawCircle(Offset(start, centerHeight), PointRadius.toPx().value, paint)
+    val start = thumbRadius + thumbPathWidth * relativePosition
+    canvas.drawCircle(
+        Offset(start.toPx().value, centerHeight.value),
+        // TODO(malkov): wierd +1 but necessary in order to properly cover track. Investigate
+        thumbRadius.toPx().value + 1,
+        paint
+    )
 }
 
 private val RelativeThumbTranslationProp = FloatPropKey()
 private val ThumbColorProp = ColorPropKey()
 private const val SwitchAnimationDuration = 100
 
-private fun generateTransitionDefinition(activeColor: Color) = transitionDefinition {
-    fun <T> TransitionSpec.switchTween() = tween<T> {
-        duration = SwitchAnimationDuration
+private fun generateTransitionDefinition(checkedColor: Color, uncheckedColor: Color) =
+    transitionDefinition {
+        fun <T> TransitionSpec.switchTween() = tween<T> {
+            duration = SwitchAnimationDuration
+            easing = FastOutSlowInEasing
+        }
+
+        state(false) {
+            this[RelativeThumbTranslationProp] = 0f
+            this[ThumbColorProp] = uncheckedColor
+        }
+        state(true) {
+            this[RelativeThumbTranslationProp] = 1f
+            this[ThumbColorProp] = checkedColor
+        }
+        transition(fromState = false, toState = true) {
+            RelativeThumbTranslationProp using switchTween()
+            ThumbColorProp using switchTween()
+        }
+        transition(fromState = true, toState = false) {
+            RelativeThumbTranslationProp using switchTween()
+            ThumbColorProp using switchTween()
+        }
     }
 
-    state(false) {
-        this[RelativeThumbTranslationProp] = 0f
-        this[ThumbColorProp] = UncheckedThumbColor
-    }
-    state(true) {
-        this[RelativeThumbTranslationProp] = 1f
-        this[ThumbColorProp] = activeColor
-    }
-    transition(fromState = false, toState = true) {
-        RelativeThumbTranslationProp using switchTween()
-        ThumbColorProp using switchTween()
-    }
-    transition(fromState = true, toState = false) {
-        RelativeThumbTranslationProp using switchTween()
-        ThumbColorProp using switchTween()
-    }
-}
+private val CheckedTrackOpacity = 0.54f
+private val UncheckedTrackOpacity = 0.38f
 
-// TODO(malkov): see how it goes and maybe move it to styles or cross-widget defaults
-private val UncheckedThumbColor = Color(0xFFEBEBEB.toInt())
-private val UncheckedTrackColor = Color(0xFF7D7D7D.toInt())
-private const val TrackAlpha = 75
+private val TrackWidth = 34.dp
+private val TrackStrokeWidth = 14.dp
 
-// TODO(malkov): random numbers which produce the same switch as android.widget.Switch
-private val MinWidth = 47.5.dp
-private val MinHeight = 27.25.dp
+private val ThumbDiameter = 20.dp
 
-private val TrackHeight = 14.dp
-private val TrackWidth = 11.dp
-private val PointRadius = 10.dp
\ No newline at end of file
+// TODO(malkov): clarify this padding for Switch
+private val DefaultSwitchPadding = 2.dp
+private val SwitchWidth = TrackWidth
+private val SwitchHeight = ThumbDiameter
\ No newline at end of file
diff --git a/work/workmanager-gcm/src/androidTest/java/androidx/work/impl/background/gcm/WorkManagerGcmDispatcherTest.kt b/work/workmanager-gcm/src/androidTest/java/androidx/work/impl/background/gcm/WorkManagerGcmDispatcherTest.kt
index b04c246..1948994 100644
--- a/work/workmanager-gcm/src/androidTest/java/androidx/work/impl/background/gcm/WorkManagerGcmDispatcherTest.kt
+++ b/work/workmanager-gcm/src/androidTest/java/androidx/work/impl/background/gcm/WorkManagerGcmDispatcherTest.kt
@@ -22,7 +22,7 @@
 import androidx.arch.core.executor.TaskExecutor
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
+import androidx.test.filters.MediumTest
 import androidx.work.Configuration
 import androidx.work.impl.WorkManagerImpl
 import androidx.work.impl.utils.SynchronousExecutor
@@ -36,7 +36,7 @@
 import java.util.concurrent.Executor
 
 @RunWith(AndroidJUnit4::class)
-@SmallTest
+@MediumTest
 class WorkManagerGcmDispatcherTest {
     lateinit var mContext: Context
     lateinit var mExecutor: Executor