Convert static app shortcuts to dynamic

Will allow user customization in the future (colors, choosing which show up in list, etc.)
This commit is contained in:
Adrian Campos 2017-03-09 10:45:44 -08:00 committed by Karim Abou Zeid
commit 43a2f319fc
10 changed files with 216 additions and 93 deletions

View file

@ -117,37 +117,3 @@ dependencies {
compile 'com.jakewharton:butterknife:8.5.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
}
// Add support for placeholders in resource files.
// Required so that packagename can be referenced in xml. https://code.google.com/p/android/issues/detail?id=69224#c12
def replacePlaceholdersInFile(basePath, fileName, placeholders) {
def file = new File(basePath, fileName);
if (!file.exists()) {
logger.quiet("Unable to replace placeholders in " + file.toString() + ". File cannot be found.")
return;
}
logger.debug("Replacing placeholders in " + file.toString())
logger.debug("Placeholders: " + placeholders.toString())
def content = file.getText('UTF-8')
placeholders.each { entry ->
content = content.replaceAll("\\\$\\{${entry.key}\\}", entry.value)
}
file.write(content, 'UTF-8')
}
afterEvaluate {
android.applicationVariants.all { variant ->
variant.outputs.each { output ->
output.processResources.doFirst {
// prepare placeholder map from manifestPlaceholders including applicationId placeholder
def placeholders = variant.mergedFlavor.manifestPlaceholders + [applicationId: variant.applicationId]
replacePlaceholdersInFile(resDir, 'xml/launcher_shortcuts.xml', placeholders)
}
}
}
}

View file

@ -29,8 +29,6 @@
<category android:name="android.intent.category.APP_MUSIC" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="android.app.shortcuts"
android:resource="@xml/launcher_shortcuts" />
<intent-filter>
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />

View file

@ -30,7 +30,7 @@ public class AppShortcutLauncherActivity extends Activity {
Bundle extras = getIntent().getExtras();
if (extras!=null){
try {
shortcutType = ShortcutType.valueOf(extras.getString(getString(R.string.id_shortcuttype)));
shortcutType = ShortcutType.valueOf(extras.getString(KEY_SHORTCUT_TYPE));
} catch (IllegalArgumentException e){ //In the event we're somehow passed an invalid enum string, don't crash.
e.printStackTrace();
shortcutType = ShortcutType.NONE;
@ -64,7 +64,7 @@ public class AppShortcutLauncherActivity extends Activity {
}
enum PlayMode {NORMAL, SHUFFLE}
private enum PlayMode {NORMAL, SHUFFLE}
private void launchMainActivityWithSongs(PlayMode playMode, ArrayList<Song> songs){
//Create a new intent to launch MainActivity
Intent intent = new Intent(this, MainActivity.class);
@ -93,6 +93,7 @@ public class AppShortcutLauncherActivity extends Activity {
Toast.makeText(getApplicationContext(), R.string.error_launching_shortcut, Toast.LENGTH_LONG).show();
}
public static final String KEY_SHORTCUT_TYPE = "com.kabouzeid.gramophone.appshortcuts.ShortcutType";
public enum ShortcutType {
SHUFFLE_ALL, TOP_TRACKS, LAST_ADDED, NONE
}

View file

@ -0,0 +1,66 @@
package com.kabouzeid.gramophone.appshortcuts;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.Color;
import android.graphics.drawable.Icon;
import com.kabouzeid.gramophone.appshortcuts.shortcuttype.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Adrian Campos
*/
@TargetApi(25)
public class DynamicShortcutManager {
Context mContext;
ShortcutManager shortcutManager;
public DynamicShortcutManager(Context context){
mContext = context;
shortcutManager = mContext.getSystemService(ShortcutManager.class);
}
public void initDynamicShortcuts(){
if (shortcutManager.getDynamicShortcuts().size() == 0){
shortcutManager.setDynamicShortcuts(getDefaultShortcuts());
}
}
public List<ShortcutInfo> getDefaultShortcuts(){
return (Arrays.asList(
new ShuffleAllShortcutType(mContext).getShortcutInfo(),
new TopTracksShortcutType(mContext).getShortcutInfo(),
new LastAddedShortcutType(mContext).getShortcutInfo()
));
}
public static ShortcutInfo createShortcut(Context context, String id, String shortLabel, String longLabel, Icon icon, Intent intent){
return new ShortcutInfo.Builder(context, id)
.setShortLabel(shortLabel)
.setLongLabel(longLabel)
.setIcon(icon)
.setIntent(intent)
.build();
}
public void tintShortcutIcons(ArrayList<ShortcutInfo> shortcutInfos, Color color){
for (ShortcutInfo shortcutInfo : shortcutInfos) {
tintShortcutIcon(shortcutInfo, color);
}
}
public void tintShortcutIcon(ShortcutInfo shortcutInfo, Color color){
//TODO Tint icons here
}
}

View file

@ -0,0 +1,55 @@
package com.kabouzeid.gramophone.appshortcuts.shortcuttype;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.os.Bundle;
import com.kabouzeid.gramophone.appshortcuts.AppShortcutLauncherActivity;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.ui.activities.MainActivity;
import java.util.ArrayList;
/**
* @author Adrian Campos
*/
@TargetApi(25)
public abstract class BaseShortcutType {
static final String ID_PREFIX = "com.kabouzeid.gramophone.appshortcuts.id.";
Context mContext;
public BaseShortcutType(Context context) {
mContext = context;
}
abstract ShortcutInfo getShortcutInfo();
/**
* Creates an Intent that will launch MainActivtiy and immediately play {@param songs} in either shuffle or normal mode
*
* @param shortcutType Describes the type of shortcut to create (ShuffleAll, TopTracks, custom playlist, etc.)
* @return
*/
Intent getPlaySongsIntent(AppShortcutLauncherActivity.ShortcutType shortcutType) {
//Create a new intent to launch MainActivity
Intent intent = new Intent(mContext, AppShortcutLauncherActivity.class);
intent.setAction(Intent.ACTION_VIEW);
//Create a bundle to store instructions for AppShortcutLauncherActivity
Bundle b = new Bundle();
b.putString(AppShortcutLauncherActivity.KEY_SHORTCUT_TYPE, shortcutType.toString());
//Put bundle in intent
intent.putExtras(b);
return intent;
}
}

View file

@ -0,0 +1,29 @@
package com.kabouzeid.gramophone.appshortcuts.shortcuttype;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Icon;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.appshortcuts.AppShortcutLauncherActivity;
/**
* @author Adrian Campos
*/
@TargetApi(25)
public final class LastAddedShortcutType extends BaseShortcutType {
public LastAddedShortcutType(Context context) {
super(context);
}
public ShortcutInfo getShortcutInfo() {
return new ShortcutInfo.Builder(mContext, ID_PREFIX + "last_added")
.setShortLabel(mContext.getString(R.string.appshortcut_lastadded_short))
.setLongLabel(mContext.getString(R.string.appshortcut_lastadded_long))
.setIcon(Icon.createWithResource(mContext, R.drawable.ic_library_add_white_24dp))
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.ShortcutType.LAST_ADDED))
.build();
}
}

View file

@ -0,0 +1,29 @@
package com.kabouzeid.gramophone.appshortcuts.shortcuttype;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Icon;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.appshortcuts.AppShortcutLauncherActivity;
/**
* @author Adrian Campos
*/
@TargetApi(25)
public final class ShuffleAllShortcutType extends BaseShortcutType {
public ShuffleAllShortcutType(Context context) {
super(context);
}
public ShortcutInfo getShortcutInfo() {
return new ShortcutInfo.Builder(mContext, ID_PREFIX + "shuffle_all")
.setShortLabel(mContext.getString(R.string.appshortcut_shuffleall_short))
.setLongLabel(mContext.getString(R.string.appshortcut_shuffleall_long))
.setIcon(Icon.createWithResource(mContext, R.drawable.ic_shuffle_white_24dp))
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.ShortcutType.SHUFFLE_ALL))
.build();
}
}

View file

@ -0,0 +1,30 @@
package com.kabouzeid.gramophone.appshortcuts.shortcuttype;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Icon;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.appshortcuts.AppShortcutLauncherActivity;
import com.kabouzeid.gramophone.loader.TopAndRecentlyPlayedTracksLoader;
/**
* @author Adrian Campos
*/
@TargetApi(25)
public final class TopTracksShortcutType extends BaseShortcutType {
public TopTracksShortcutType(Context context) {
super(context);
}
public ShortcutInfo getShortcutInfo() {
return new ShortcutInfo.Builder(mContext, ID_PREFIX + "top_tracks")
.setShortLabel(mContext.getString(R.string.appshortcut_toptracks_short))
.setLongLabel(mContext.getString(R.string.appshortcut_toptracks_long))
.setIcon(Icon.createWithResource(mContext, R.drawable.ic_trending_up_white_24dp))
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.ShortcutType.TOP_TRACKS))
.build();
}
}

View file

@ -28,6 +28,7 @@ import com.kabouzeid.appthemehelper.ThemeStore;
import com.kabouzeid.appthemehelper.util.ATHUtil;
import com.kabouzeid.appthemehelper.util.NavigationViewUtil;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.appshortcuts.DynamicShortcutManager;
import com.kabouzeid.gramophone.dialogs.ChangelogDialog;
import com.kabouzeid.gramophone.dialogs.DonationsDialog;
import com.kabouzeid.gramophone.glide.SongGlideRequest;
@ -112,6 +113,9 @@ public class MainActivity extends AbsSlidingMusicPanelActivity {
if (!checkShowIntro()) {
checkShowChangelog();
}
//Set up dynamic shortcuts if needed
new DynamicShortcutManager(getApplicationContext()).initDynamicShortcuts();
}
private void setMusicChooser(int key) {

View file

@ -1,55 +0,0 @@
<shortcuts
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
tools:targetApi="25">
<shortcut
android:shortcutId="shuffle_all"
android:enabled="true"
android:icon="@drawable/ic_shuffle_white_24dp"
android:shortcutShortLabel="@string/appshortcut_shuffleall_short"
android:shortcutLongLabel="@string/appshortcut_shuffleall_long">
<intent
android:action="android.intent.action.VIEW"
android:targetClass="com.kabouzeid.gramophone.appshortcuts.AppShortcutLauncherActivity"
android:targetPackage="${applicationId}">
<extra
android:name="com.kabouzeid.gramophone.appshortcuts.ShortcutType"
android:value="SHUFFLE_ALL" />
</intent>
</shortcut>
<shortcut
android:shortcutId="top_tracks"
android:enabled="true"
android:icon="@drawable/ic_trending_up_white_24dp"
android:shortcutShortLabel="@string/appshortcut_toptracks_short"
android:shortcutLongLabel="@string/appshortcut_toptracks_long"
>
<intent
android:action="android.intent.action.VIEW"
android:targetClass="com.kabouzeid.gramophone.appshortcuts.AppShortcutLauncherActivity"
android:targetPackage="${applicationId}">
<extra
android:name="com.kabouzeid.gramophone.appshortcuts.ShortcutType"
android:value="TOP_TRACKS" />
</intent>
</shortcut>
<shortcut
android:shortcutId="last_added"
android:enabled="true"
android:icon="@drawable/ic_library_add_white_24dp"
android:shortcutShortLabel="@string/appshortcut_lastadded_short"
android:shortcutLongLabel="@string/appshortcut_lastadded_long"
>
<intent
android:action="android.intent.action.VIEW"
android:targetClass="com.kabouzeid.gramophone.appshortcuts.AppShortcutLauncherActivity"
android:targetPackage="${applicationId}">
<extra
android:name="com.kabouzeid.gramophone.appshortcuts.ShortcutType"
android:value="LAST_ADDED" />
</intent>
</shortcut>
</shortcuts>