Update plugin waking code, fix crash on Oreo devices (#840)

* Update plugin waking code, fix crash on Oreo devices

In Android Oreo we can't use services without bringing them to the
foreground, i.e. showing icon and following specified lifecycle.

After some consideration the new way was implemented for plugin system.
Plugins will no longer have bound service and instead will do everything
required from within their activities. All background logic that
previously resided in services will now be performed before the activity
has even shown its window. This greatly reduces complexity and cost
associated with bringing service model in accordance with Oreo
guidelines. The only downside to this approach is small flickering
or pause in emulators as activities still expect to show themselves
on start instead of disappearing again.

* Move value to class-level constant
This commit is contained in:
Antic1tizen One 2018-09-29 11:47:47 +03:00 committed by Adrian Ulrich
parent fca6f14ab2
commit 45b6063515
3 changed files with 37 additions and 8 deletions

View File

@ -30,6 +30,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
@ -49,6 +50,7 @@ import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.Menu;
@ -70,6 +72,12 @@ public abstract class PlaybackActivity extends Activity
View.OnClickListener,
CoverView.Callback
{
/**
* This constant is unavailable on Android < N.
* For newer versions the constant is {@link Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND}
*/
private static final int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;
private Action mUpAction;
private Action mDownAction;
@ -733,12 +741,14 @@ public abstract class PlaybackActivity extends Activity
*
* @param songIntent intent containing song id as {@link Long} in its "id" extra.
*/
@SuppressLint("WrongConstant") // flag is ignored on Android < 7.0
protected void queryPluginsForIntent(Intent songIntent) {
// obtain list of plugins anew - some plugins may be installed/deleted
mPlugins.clear();
mLastRequestedCtx = songIntent;
Intent requestPlugins = new Intent(PluginUtils.ACTION_REQUEST_PLUGIN_PARAMS);
requestPlugins.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
requestPlugins.addFlags(FLAG_RECEIVER_INCLUDE_BACKGROUND);
sendBroadcast(requestPlugins);
}
@ -793,7 +803,11 @@ public abstract class PlaybackActivity extends Activity
request.putExtra(PluginUtils.EXTRA_PARAM_SONG_TITLE, resolved.title);
request.putExtra(PluginUtils.EXTRA_PARAM_SONG_ARTIST, resolved.artist);
request.putExtra(PluginUtils.EXTRA_PARAM_SONG_ALBUM, resolved.album);
startService(request);
if (request.resolveActivity(getPackageManager()) != null) {
startActivity(request);
} else {
Log.e("PluginSystem", "Couldn't start plugin activity for " + request);
}
}
mLastRequestedCtx = null;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 Oleg Chernovskiy <adonai@xaker.ru>
* Copyright (C) 2016-2018 Oleg Chernovskiy <adonai@xaker.ru>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -18,7 +18,9 @@ package ch.blinkenlights.android.vanilla;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.widget.Toast;
import java.util.List;
@ -52,16 +54,28 @@ public class PluginUtils {
static final String EXTRA_PLUGIN_MAP = "ch.blinkenlights.android.vanilla.internal.extra.PLUGIN_MAP";
public static boolean checkPlugins(Context ctx) {
List<ResolveInfo> resolved = ctx.getPackageManager().queryBroadcastReceivers(new Intent(ACTION_REQUEST_PLUGIN_PARAMS), 0);
if(!resolved.isEmpty()) {
// If plugin is just installed, Android will not deliver intents to its receiver
// until it's started at least one time
PackageManager pm = ctx.getPackageManager();
List<ResolveInfo> resolved = pm.queryBroadcastReceivers(new Intent(ACTION_REQUEST_PLUGIN_PARAMS), 0);
if (!resolved.isEmpty()) {
// If plugin is just installed, Android will not deliver intents
// to its receiver until it's started at least one time
boolean hasPlugins = false;
for (ResolveInfo ri : resolved) {
Intent awaker = new Intent(ACTION_WAKE_PLUGIN);
awaker.setPackage(ri.activityInfo.packageName);
ctx.startService(awaker);
// all plugins must have respective activity that can handle ACTION_WAKE_PLUGIN
if (awaker.resolveActivity(pm) != null) {
hasPlugins = true;
ctx.startActivity(awaker);
} else {
// need to upgrade the plugin from service-based plugin system to activity-based
CharSequence pluginName = ri.loadLabel(pm);
String error = String.format(ctx.getString(R.string.plugin_needs_upgrade), pluginName);
Toast.makeText(ctx, error, Toast.LENGTH_SHORT).show();
}
}
return true;
return hasPlugins;
}
return false;

View File

@ -381,6 +381,7 @@ THE SOFTWARE.
<string name="folder_neutral">Neutral</string>
<!-- Plugin system -->
<string name="plugins">Plugins</string>
<string name="plugin_needs_upgrade">Please upgrade plugin %s to the latest version</string>
<!-- Theme names -->
<string name="theme_name_standard_light">Standard</string>