Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adopt target SDK 34 #1713

Merged
merged 16 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## Version 5.0.3 (In development)

### App Center Distribute

* **[Fix]** Add RECEIVER_EXPORTED flag for install receiver.
* **[Fix]** Add FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT flag for broadcast pending intent.

## Version 5.0.2

### AppCenter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.FileObserver;
import android.preference.CheckBoxPreference;
Expand Down Expand Up @@ -738,7 +739,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == FILE_ATTACHMENT_DIALOG_ID) {
Uri fileAttachment = resultCode == RESULT_OK && data != null ? data.getData() : null;
if (fileAttachment != null) {
getActivity().getContentResolver().takePersistableUriPermission(fileAttachment, data.getFlags() & Intent.FLAG_GRANT_READ_URI_PERMISSION);
getActivity().getContentResolver().takePersistableUriPermission(fileAttachment, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
MainActivity.setFileAttachment(fileAttachment);
Preference preference = getPreferenceManager().findPreference(getString(R.string.appcenter_crashes_file_attachment_key));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import static com.microsoft.appcenter.distribute.DistributeConstants.LOG_TAG;

import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
Expand All @@ -32,6 +33,15 @@ class InstallStatusReceiver extends BroadcastReceiver {
@VisibleForTesting
static final String INSTALL_STATUS_ACTION = "com.microsoft.appcenter.action.INSTALL_STATUS";

/**
* Raw value of PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT.
* https://developer.android.com/reference/android/app/PendingIntent#FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT
* This flag will appear only in Android target SDK 34.
*/
@VisibleForTesting
private static final int FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT_VALUE = 16777216;


static IntentFilter getInstallerReceiverFilter() {
IntentFilter installerReceiverFilter = new IntentFilter();
installerReceiverFilter.addAction(INSTALL_STATUS_ACTION);
Expand All @@ -49,8 +59,12 @@ static IntentSender getInstallStatusIntentSender(Context context, int requestCod
int broadcastFlags = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
broadcastFlags = PendingIntent.FLAG_MUTABLE;
if (Build.VERSION.SDK_INT >= 34) {
broadcastFlags |= FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT_VALUE;
}
}
PendingIntent pendingIntent = PendingIntent.getBroadcast(
// Suppress the warning as the flag PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT is unavailable on Android SDK < 34.
@SuppressLint("WrongConstant") PendingIntent pendingIntent = PendingIntent.getBroadcast(
context,
requestCode,
new Intent(INSTALL_STATUS_ACTION),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import android.content.IntentSender;
import android.content.pm.PackageInstaller;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.ParcelFileDescriptor;

Expand Down Expand Up @@ -233,7 +234,11 @@ private synchronized void registerListeners() {
if (mInstallStatusReceiver == null) {
AppCenterLog.debug(LOG_TAG, "Register receiver for installing a new release.");
mInstallStatusReceiver = new InstallStatusReceiver(this);
mContext.registerReceiver(mInstallStatusReceiver, InstallStatusReceiver.getInstallerReceiverFilter());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
mContext.registerReceiver(mInstallStatusReceiver, InstallStatusReceiver.getInstallerReceiverFilter(), Context.RECEIVER_EXPORTED);
} else {
mContext.registerReceiver(mInstallStatusReceiver, InstallStatusReceiver.getInstallerReceiverFilter());
}
}
if (mSessionCallback == null) {
PackageInstaller packageInstaller = getPackageInstaller();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
public class InstallStatusReceiverTest {

private static final int SESSION_ID = 42;
private static final int FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT_VALUE = 16777216;

@Rule
public PowerMockRule mRule = new PowerMockRule();
Expand Down Expand Up @@ -216,6 +217,14 @@ public void installerReceiverFilter() throws Exception {
verify(filter).addAction(INSTALL_STATUS_ACTION);
}

@Test
public void createIntentSenderOnAndroid34() {

/* Mock SDK_INT to 34 target SDK. */
Whitebox.setInternalState(Build.VERSION.class, "SDK_INT", 34);
createIntentSender(PendingIntent.FLAG_MUTABLE | FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT_VALUE);
}

@Test
public void createIntentSenderOnAndroidS() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.ParcelFileDescriptor;

Expand All @@ -41,12 +42,14 @@
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.powermock.reflect.Whitebox;

import java.io.FileInputStream;
import java.io.IOException;
Expand All @@ -58,7 +61,7 @@
InstallStatusReceiver.class,
PackageInstallerListener.class,
ReleaseInstallerActivity.class,
SessionReleaseInstaller.class
SessionReleaseInstaller.class,
})
public class SessionReleaseInstallerTest {

Expand Down Expand Up @@ -153,7 +156,9 @@ public Boolean answer(InvocationOnMock invocation) {
}

@Test
public void installSuccess() throws IOException {
public void installSuccessForSV2() throws IOException {
Whitebox.setInternalState(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.S_V2);

Uri uri = mock(Uri.class);
mInstaller.install(uri);

Expand All @@ -177,6 +182,33 @@ public void installSuccess() throws IOException {
verify(mPackageInstaller).abandonSession(eq(SESSION_ID));
}

@Test
public void installSuccessForTiramisu() throws IOException {
Whitebox.setInternalState(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);

Uri uri = mock(Uri.class);
mInstaller.install(uri);

/* Verify that all required things called. */
verify(mHandler).post(any(Runnable.class));
verify(mContext).registerReceiver(eq(mInstallStatusReceiver), any(), anyInt());
verify(mPackageInstaller).registerSessionCallback(eq(mPackageInstallerListener));
verify(mInputStream).close();
verify(mOutputStream).close();
verify(mSession).commit(any(IntentSender.class));
verify(mSession, never()).abandon();
verify(mSession).close();
verifyNoInteractions(mListener);

/* Try to star install second time. It's valid case if something goes wrong with previous try. */
mInstaller.install(uri);

/* Cancel previous session and re-use callbacks. */
verify(mContext).registerReceiver(eq(mInstallStatusReceiver), any(), anyInt());
verify(mPackageInstaller).registerSessionCallback(eq(mPackageInstallerListener));
verify(mPackageInstaller).abandonSession(eq(SESSION_ID));
}

@Test
public void throwIOExceptionWhenTryToOpenWriteSession() throws IOException {

Expand Down Expand Up @@ -246,7 +278,7 @@ public void clear() {
mInstaller.install(uri);

/* Registering callbacks. */
verify(mContext).registerReceiver(eq(mInstallStatusReceiver), any());
verify(mContext).registerReceiver(eq(mInstallStatusReceiver), any(), anyInt());
verify(mPackageInstaller).registerSessionCallback(eq(mPackageInstallerListener));

/* Clear after start should clear registered callbacks and abandon the session. */
Expand Down
Loading