forked from organicmaps/organicmaps
[android] Fix SecurityException when importing bookmarks
SecurityException is thrown by ContentResolver.query() when called on a cold start from an Activity without FLAG_GRANT_READ_URI_PERMISSION. This flag is set automatically by the system when the app is launched with an external uri (i.e. content://). The previous implementation just lost all passed intent flags during Splash -> DownloadLegacy -> MwmActivity flow. Re-route the original intent from the system by calling setComponent() instead of wrapping it into EXTRA_INITIAL_INTENT. The original intent retains all the flags and a uri payload. Check for system's FLAG_ACTIVITY_FORWARD_RESULT instead of our custom EXTRA_PICK_POINT to detect when API caller expects a result from the call. This approach is backward-compatible and doesn't break old API clients. EXTRA_PICK_POINT can be safely removed from API callers. Remove legacy EXTRA_ACTIVITY_TO_START which wasn't used in the code. Fixes #6944 #7149 Signed-off-by: Roman Tsisyk <roman@tsisyk.com>
This commit is contained in:
parent
cde002cc63
commit
c90c6bbd71
6 changed files with 21 additions and 96 deletions
|
@ -2,6 +2,7 @@ package app.organicmaps;
|
|||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
|
@ -35,6 +36,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|||
import com.google.android.material.progressindicator.LinearProgressIndicator;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@SuppressLint("StringFormatMatches")
|
||||
public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
||||
|
@ -60,9 +62,6 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
|||
@Nullable
|
||||
private Dialog mAlertDialog;
|
||||
|
||||
@NonNull
|
||||
private ActivityResultLauncher<Intent> mApiRequest;
|
||||
|
||||
private boolean mAreResourcesDownloaded;
|
||||
|
||||
private static final int DOWNLOAD = 0;
|
||||
|
@ -190,10 +189,6 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
|||
super.onSafeCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_download_resources);
|
||||
initViewsAndListeners();
|
||||
mApiRequest = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
|
||||
setResult(result.getResultCode(), result.getData());
|
||||
finish();
|
||||
});
|
||||
|
||||
if (prepareFilesDownload(false))
|
||||
{
|
||||
|
@ -212,8 +207,6 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
|||
protected void onSafeDestroy()
|
||||
{
|
||||
super.onSafeDestroy();
|
||||
mApiRequest.unregister();
|
||||
mApiRequest = null;
|
||||
Utils.keepScreenOn(Config.isKeepScreenOnEnabled(), getWindow());
|
||||
if (mCountryDownloadListenerSlot != 0)
|
||||
{
|
||||
|
@ -348,21 +341,14 @@ public class DownloadResourcesLegacyActivity extends BaseMwmFragmentActivity
|
|||
if (!mAreResourcesDownloaded)
|
||||
return;
|
||||
|
||||
final Intent intent = new Intent(this, MwmActivity.class);
|
||||
// Re-use original intent to retain all flags and payload.
|
||||
// https://github.com/organicmaps/organicmaps/issues/6944
|
||||
final Intent intent = Objects.requireNonNull(getIntent());
|
||||
intent.setComponent(new ComponentName(this, MwmActivity.class));
|
||||
|
||||
// Disable animation because MwmActivity should appear exactly over this one
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
|
||||
// See {@link SplashActivity.processNavigation()}
|
||||
final Intent initialIntent = getIntent();
|
||||
intent.putExtra(SplashActivity.EXTRA_INITIAL_INTENT, initialIntent);
|
||||
if (Factory.isStartedForApiResult(initialIntent))
|
||||
{
|
||||
// Wait for the result from MwmActivity for API callers.
|
||||
mApiRequest.launch(intent);
|
||||
return;
|
||||
}
|
||||
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
|
|
|
@ -114,7 +114,6 @@ import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
|
|||
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
|
||||
import static android.Manifest.permission.POST_NOTIFICATIONS;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
import static app.organicmaps.SplashActivity.EXTRA_INITIAL_INTENT;
|
||||
import static app.organicmaps.location.LocationState.FOLLOW;
|
||||
import static app.organicmaps.location.LocationState.FOLLOW_AND_ROTATE;
|
||||
import static app.organicmaps.location.LocationState.LOCATION_TAG;
|
||||
|
@ -1003,10 +1002,6 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||
@Override
|
||||
protected void onNewIntent(Intent intent)
|
||||
{
|
||||
// {@link see BaseMwmFragmentActivity.onCreate()}
|
||||
final Intent initialIntent = IntentCompat.getParcelableExtra(intent, EXTRA_INITIAL_INTENT, Intent.class);
|
||||
if (initialIntent != null)
|
||||
intent = initialIntent;
|
||||
setIntent(intent);
|
||||
super.onNewIntent(intent);
|
||||
if (isMapRendererActive())
|
||||
|
|
|
@ -4,6 +4,7 @@ import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
|
|||
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
@ -28,12 +29,11 @@ import app.organicmaps.util.log.Logger;
|
|||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
public class SplashActivity extends AppCompatActivity
|
||||
{
|
||||
private static final String TAG = SplashActivity.class.getSimpleName();
|
||||
private static final String EXTRA_ACTIVITY_TO_START = "extra_activity_to_start";
|
||||
public static final String EXTRA_INITIAL_INTENT = "extra_initial_intent";
|
||||
|
||||
private static final long DELAY = 100;
|
||||
|
||||
|
@ -42,25 +42,10 @@ public class SplashActivity extends AppCompatActivity
|
|||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
@NonNull
|
||||
private ActivityResultLauncher<String[]> mPermissionRequest;
|
||||
@NonNull
|
||||
private ActivityResultLauncher<Intent> mApiRequest;
|
||||
|
||||
@NonNull
|
||||
private final Runnable mInitCoreDelayedTask = this::init;
|
||||
|
||||
@NonNull
|
||||
public static void start(@NonNull Context context,
|
||||
@Nullable Class<? extends Activity> activityToStart,
|
||||
@Nullable Intent initialIntent)
|
||||
{
|
||||
Intent intent = new Intent(context, SplashActivity.class);
|
||||
if (activityToStart != null)
|
||||
intent.putExtra(EXTRA_ACTIVITY_TO_START, activityToStart);
|
||||
if (initialIntent != null)
|
||||
intent.putExtra(EXTRA_INITIAL_INTENT, initialIntent);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState)
|
||||
{
|
||||
|
@ -79,10 +64,6 @@ public class SplashActivity extends AppCompatActivity
|
|||
setContentView(R.layout.activity_splash);
|
||||
mPermissionRequest = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(),
|
||||
result -> Config.setLocationRequested());
|
||||
mApiRequest = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
|
||||
setResult(result.getResultCode(), result.getData());
|
||||
finish();
|
||||
});
|
||||
|
||||
if (DisplayManager.from(this).isCarDisplayUsed())
|
||||
{
|
||||
|
@ -123,8 +104,6 @@ public class SplashActivity extends AppCompatActivity
|
|||
super.onDestroy();
|
||||
mPermissionRequest.unregister();
|
||||
mPermissionRequest = null;
|
||||
mApiRequest.unregister();
|
||||
mApiRequest = null;
|
||||
}
|
||||
|
||||
private void showFatalErrorDialog(@StringRes int titleId, @StringRes int messageId)
|
||||
|
@ -174,30 +153,13 @@ public class SplashActivity extends AppCompatActivity
|
|||
return;
|
||||
}
|
||||
|
||||
Intent input = getIntent();
|
||||
Intent result = new Intent(this, DownloadResourcesLegacyActivity.class);
|
||||
if (input != null)
|
||||
{
|
||||
if (input.hasExtra(EXTRA_ACTIVITY_TO_START))
|
||||
{
|
||||
result = new Intent(this,
|
||||
(Class<? extends Activity>) input.getSerializableExtra(EXTRA_ACTIVITY_TO_START));
|
||||
}
|
||||
|
||||
Intent initialIntent = input.hasExtra(EXTRA_INITIAL_INTENT) ?
|
||||
IntentCompat.getParcelableExtra(input, EXTRA_INITIAL_INTENT, Intent.class) :
|
||||
input;
|
||||
result.putExtra(EXTRA_INITIAL_INTENT, initialIntent);
|
||||
if (Factory.isStartedForApiResult(initialIntent))
|
||||
{
|
||||
// Wait for the result from MwmActivity for API callers.
|
||||
mApiRequest.launch(result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Re-use original intent to retain all flags and payload.
|
||||
// https://github.com/organicmaps/organicmaps/issues/6944
|
||||
final Intent intent = Objects.requireNonNull(getIntent());
|
||||
intent.setComponent(new ComponentName(this, DownloadResourcesLegacyActivity.class));
|
||||
|
||||
Config.setFirstStartDialogSeen(this);
|
||||
startActivity(result);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,6 @@ public class Const
|
|||
public static final String EXTRA_PREFIX = AUTHORITY + ".extra";
|
||||
public static final String ACTION_PREFIX = AUTHORITY + ".action";
|
||||
|
||||
// Request extras
|
||||
public static final String EXTRA_PICK_POINT = EXTRA_PREFIX + ".PICK_POINT";
|
||||
|
||||
// Response extras
|
||||
public static final String EXTRA_POINT_NAME = EXTRA_PREFIX + ".POINT_NAME";
|
||||
public static final String EXTRA_POINT_LAT = EXTRA_PREFIX + ".POINT_LAT";
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package app.organicmaps.base;
|
||||
|
||||
import static app.organicmaps.SplashActivity.EXTRA_INITIAL_INTENT;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioManager;
|
||||
|
@ -28,6 +27,8 @@ import app.organicmaps.util.ThemeUtils;
|
|||
import app.organicmaps.util.concurrency.UiThread;
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class BaseMwmFragmentActivity extends AppCompatActivity
|
||||
{
|
||||
private static final String TAG = BaseMwmFragmentActivity.class.getSimpleName();
|
||||
|
@ -65,20 +66,12 @@ public abstract class BaseMwmFragmentActivity extends AppCompatActivity
|
|||
mThemeName = Config.getCurrentUiTheme(getApplicationContext());
|
||||
setTheme(getThemeResourceId(mThemeName));
|
||||
RtlUtils.manageRtl(this);
|
||||
// An intent that was skipped due to core wasn't initialized has to be used
|
||||
// as a target intent for this activity, otherwise all input extras will be lost
|
||||
// in a splash activity loop.
|
||||
final Intent intent = getIntent();
|
||||
if (intent != null)
|
||||
{
|
||||
final Intent initialIntent = IntentCompat.getParcelableExtra(intent, EXTRA_INITIAL_INTENT, Intent.class);
|
||||
if (initialIntent != null)
|
||||
setIntent(initialIntent);
|
||||
}
|
||||
|
||||
if (!MwmApplication.from(this).arePlatformAndCoreInitialized())
|
||||
{
|
||||
goToSplashScreen(getIntent());
|
||||
final Intent intent = Objects.requireNonNull(getIntent());
|
||||
intent.setComponent(new ComponentName(this, SplashActivity.class));
|
||||
startActivity(intent);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -260,10 +253,4 @@ public abstract class BaseMwmFragmentActivity extends AppCompatActivity
|
|||
{
|
||||
return android.R.id.content;
|
||||
}
|
||||
|
||||
private void goToSplashScreen(@Nullable Intent initialIntent)
|
||||
{
|
||||
SplashActivity.start(this, getClass(), initialIntent);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package app.organicmaps.intent;
|
||||
|
||||
import static app.organicmaps.api.Const.EXTRA_PICK_POINT;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
@ -32,7 +30,7 @@ public class Factory
|
|||
{
|
||||
public static boolean isStartedForApiResult(@NonNull Intent intent)
|
||||
{
|
||||
return intent.getBooleanExtra(EXTRA_PICK_POINT, false);
|
||||
return (intent.getFlags() & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0;
|
||||
}
|
||||
|
||||
public static class KmzKmlProcessor implements IntentProcessor
|
||||
|
|
Loading…
Add table
Reference in a new issue