[Chromecast] Bump minSdkVersion to 23.
Future releases will no longer support Android L. Bug: internal b/183489162 Test: build and install mediashell Change-Id: I8aa62a5b6822b32f136daa5ee3d918cadc7a2d29 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3016354 Auto-Submit: Thoren Paulson <thoren@google.com> Commit-Queue: Daniel Nicoara <dnicoara@chromium.org> Reviewed-by: Daniel Nicoara <dnicoara@chromium.org> Reviewed-by: Luke Halliwell <halliwell@chromium.org> Reviewed-by: Simeon Anfinrud <sanfin@chromium.org> Cr-Commit-Position: refs/heads/master@{#900488}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
b78f6b10f4
commit
9de6cd0594
chromecast
@ -678,7 +678,7 @@ if (is_android) {
|
||||
android_manifest = "$root_gen_dir/cast_shell_manifest/AndroidManifest.xml"
|
||||
android_manifest_dep = "//chromecast/browser/android:cast_shell_manifest"
|
||||
|
||||
min_sdk_version = 21
|
||||
min_sdk_version = 23
|
||||
target_sdk_version = 31
|
||||
|
||||
shared_libraries = [ "//chromecast/android:libcast_shell_android" ]
|
||||
|
@ -8,7 +8,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.chromium.chromecast.shell">
|
||||
|
||||
<uses-sdk android:minSdkVersion="21"/>
|
||||
<uses-sdk android:minSdkVersion="23"/>
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
@ -44,20 +44,18 @@ public class CastAudioFocusRequest {
|
||||
}
|
||||
|
||||
private int getStreamType() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (mAudioAttributes != null) {
|
||||
switch (mAudioAttributes.getContentType()) {
|
||||
case AudioAttributes.CONTENT_TYPE_MOVIE:
|
||||
case AudioAttributes.CONTENT_TYPE_MUSIC:
|
||||
return AudioManager.STREAM_MUSIC;
|
||||
case AudioAttributes.CONTENT_TYPE_SONIFICATION:
|
||||
return AudioManager.STREAM_ALARM;
|
||||
case AudioAttributes.CONTENT_TYPE_SPEECH:
|
||||
return AudioManager.STREAM_VOICE_CALL;
|
||||
case AudioAttributes.CONTENT_TYPE_UNKNOWN:
|
||||
default:
|
||||
return AudioManager.STREAM_SYSTEM;
|
||||
}
|
||||
if (mAudioAttributes != null) {
|
||||
switch (mAudioAttributes.getContentType()) {
|
||||
case AudioAttributes.CONTENT_TYPE_MOVIE:
|
||||
case AudioAttributes.CONTENT_TYPE_MUSIC:
|
||||
return AudioManager.STREAM_MUSIC;
|
||||
case AudioAttributes.CONTENT_TYPE_SONIFICATION:
|
||||
return AudioManager.STREAM_ALARM;
|
||||
case AudioAttributes.CONTENT_TYPE_SPEECH:
|
||||
return AudioManager.STREAM_VOICE_CALL;
|
||||
case AudioAttributes.CONTENT_TYPE_UNKNOWN:
|
||||
default:
|
||||
return AudioManager.STREAM_SYSTEM;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -9,7 +9,6 @@ import android.content.Context;
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.media.AudioManager;
|
||||
import android.media.audiopolicy.AudioPolicy;
|
||||
import android.os.Build;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
@ -88,35 +87,6 @@ public class CastAudioManager {
|
||||
return audioFocusLossState;
|
||||
}
|
||||
|
||||
// Only called on Lollipop and below, in an Activity's onPause() event.
|
||||
// On Lollipop and below, setStreamMute() calls are cumulative and per-application, and if
|
||||
// Activities don't unmute the streams that they mute, the stream remains muted to other
|
||||
// applications, which are unable to unmute the stream themselves. Therefore, when an Activity
|
||||
// is paused, it must unmute any streams it had muted.
|
||||
// More context in b/19964892 and b/22204758.
|
||||
@SuppressWarnings("deprecation")
|
||||
public void releaseStreamMuteIfNecessary(int streamType) {
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
|
||||
// On L, if we try to unmute a stream that is not muted, a warning Toast appears.
|
||||
// Check the stream mute state to determine whether to unmute.
|
||||
boolean isMuted = false;
|
||||
try {
|
||||
// isStreamMute() was only made public in M, but it can be accessed through
|
||||
// reflection in L.
|
||||
isMuted = (Boolean) mInternal.getClass()
|
||||
.getMethod("isStreamMute", int.class)
|
||||
.invoke(mInternal, streamType);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Can not call AudioManager.isStreamMute().", e);
|
||||
}
|
||||
|
||||
if (isMuted) {
|
||||
// Note: this is a no-op on fixed-volume devices.
|
||||
mInternal.setStreamMute(streamType, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getStreamMaxVolume(int streamType) {
|
||||
return mInternal.getStreamMaxVolume(streamType);
|
||||
}
|
||||
|
@ -144,13 +144,6 @@ public class CastWebContentsActivity extends Activity {
|
||||
mAudioManagerState.set(CastAudioManager.getAudioManager(this));
|
||||
}));
|
||||
|
||||
// Clean up stream mute state on pause events.
|
||||
mAudioManagerState.andThen(Observable.not(mResumedState))
|
||||
.map(Both::getFirst)
|
||||
.subscribe(Observers.onEnter((CastAudioManager audioManager) -> {
|
||||
audioManager.releaseStreamMuteIfNecessary(AudioManager.STREAM_MUSIC);
|
||||
}));
|
||||
|
||||
// Handle each new Intent.
|
||||
Controller<CastWebContentsSurfaceHelper.StartParams> startParamsState = new Controller<>();
|
||||
mGotIntentState.and(Observable.not(mIsFinishingState))
|
||||
|
@ -4,13 +4,9 @@
|
||||
|
||||
package org.chromium.chromecast.shell;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -184,65 +180,4 @@ public class CastAudioManagerTest {
|
||||
.closed(CastAudioManager.AudioFocusLoss.TRANSIENT_CAN_DUCK)
|
||||
.end();
|
||||
}
|
||||
|
||||
// Simulate the AudioManager mute behavior on Android L. The isStreamMute() method is present,
|
||||
// but can only be used through reflection. Mute requests are cumulative, so a stream only
|
||||
// unmutes once a equal number of setStreamMute(t, true) setStreamMute(t, false) requests have
|
||||
// been received.
|
||||
private static class LollipopAudioManager extends AudioManager {
|
||||
// Stores the number of total standing mute requests per stream.
|
||||
private final SparseIntArray mMuteState = new SparseIntArray();
|
||||
private boolean mCanCallStreamMute = true;
|
||||
|
||||
public void setCanCallStreamMute(boolean able) {
|
||||
mCanCallStreamMute = able;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStreamMute(int streamType) {
|
||||
if (!mCanCallStreamMute) {
|
||||
throw new RuntimeException("isStreamMute() disabled for testing");
|
||||
}
|
||||
return mMuteState.get(streamType, 0) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStreamMute(int streamType, boolean muteState) {
|
||||
int delta = muteState ? 1 : -1;
|
||||
int currentMuteCount = mMuteState.get(streamType, 0);
|
||||
int newMuteCount = currentMuteCount + delta;
|
||||
assert newMuteCount >= 0;
|
||||
mMuteState.put(streamType, newMuteCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(sdk = Build.VERSION_CODES.LOLLIPOP)
|
||||
public void testReleaseStreamMuteWithNoMute() {
|
||||
AudioManager fakeAudioManager = new LollipopAudioManager();
|
||||
CastAudioManager audioManager = new CastAudioManager(fakeAudioManager);
|
||||
audioManager.releaseStreamMuteIfNecessary(AudioManager.STREAM_MUSIC);
|
||||
assertFalse(fakeAudioManager.isStreamMute(AudioManager.STREAM_MUSIC));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(sdk = Build.VERSION_CODES.LOLLIPOP)
|
||||
public void testReleaseStreamMuteWithMute() {
|
||||
AudioManager fakeAudioManager = new LollipopAudioManager();
|
||||
CastAudioManager audioManager = new CastAudioManager(fakeAudioManager);
|
||||
fakeAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, true);
|
||||
assertTrue(fakeAudioManager.isStreamMute(AudioManager.STREAM_MUSIC));
|
||||
audioManager.releaseStreamMuteIfNecessary(AudioManager.STREAM_MUSIC);
|
||||
assertFalse(fakeAudioManager.isStreamMute(AudioManager.STREAM_MUSIC));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(sdk = Build.VERSION_CODES.LOLLIPOP)
|
||||
public void testHandleExceptionFromIsStreamMute() {
|
||||
LollipopAudioManager fakeAudioManager = new LollipopAudioManager();
|
||||
fakeAudioManager.setCanCallStreamMute(false);
|
||||
CastAudioManager audioManager = new CastAudioManager(fakeAudioManager);
|
||||
// This should not crash even if isStreamMute() throws an exception.
|
||||
audioManager.releaseStreamMuteIfNecessary(AudioManager.STREAM_MUSIC);
|
||||
}
|
||||
}
|
||||
|
16
chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsActivityTest.java
16
chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsActivityTest.java
@ -11,7 +11,6 @@ import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
@ -36,7 +35,6 @@ import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.shadows.ShadowActivity;
|
||||
|
||||
import org.chromium.chromecast.base.Observable;
|
||||
import org.chromium.content_public.browser.WebContents;
|
||||
import org.chromium.testing.local.LocalRobolectricTestRunner;
|
||||
|
||||
@ -48,6 +46,9 @@ import org.chromium.testing.local.LocalRobolectricTestRunner;
|
||||
@RunWith(LocalRobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class CastWebContentsActivityTest {
|
||||
/**
|
||||
* ShadowActivity that allows us to intercept calls to setTurnScreenOn.
|
||||
*/
|
||||
@Implements(Activity.class)
|
||||
public static class ExtendedShadowActivity extends ShadowActivity {
|
||||
private boolean mTurnScreenOn;
|
||||
@ -108,17 +109,6 @@ public class CastWebContentsActivityTest {
|
||||
assertNull(intent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReleasesStreamMuteIfNecessaryOnPause() {
|
||||
CastAudioManager mockAudioManager = mock(CastAudioManager.class);
|
||||
when(mockAudioManager.requestAudioFocusWhen(anyObject()))
|
||||
.thenReturn(mock(Observable.class));
|
||||
mActivity.setAudioManagerForTesting(mockAudioManager);
|
||||
mActivityLifecycle.create().start().resume();
|
||||
mActivityLifecycle.pause();
|
||||
verify(mockAudioManager).releaseStreamMuteIfNecessary(AudioManager.STREAM_MUSIC);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDropsIntentWithoutUri() {
|
||||
CastWebContentsSurfaceHelper surfaceHelper = mock(CastWebContentsSurfaceHelper.class);
|
||||
|
Reference in New Issue
Block a user