Merge "Added ColorExtractionService and ExtractedColors." into ub-launcher3-calgary

This commit is contained in:
Tony Wickham
2016-04-01 22:44:58 +00:00
committed by Android (Google) Code Review
12 changed files with 351 additions and 6 deletions
+5
View File
@@ -141,6 +141,11 @@
</intent-filter>
</receiver>
<service android:name=".dynamicui.ColorExtractionService"
android:exported="false"
android:process=":wallpaper_chooser">
</service>
<!-- The settings provider contains Home's data, like the workspace favorites -->
<provider
android:name="com.android.launcher3.LauncherProvider"
+2
View File
@@ -52,12 +52,14 @@ repositories {
dependencies {
compile 'com.android.support:support-v4:23.1.1'
compile 'com.android.support:recyclerview-v7:23.1.1'
compile 'com.android.support:palette-v7:23.2.0'
compile 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-2'
compile project(":WallpaperPicker-Lib")
testCompile 'junit:junit:4.12'
androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
androidTestCompile 'com.android.support:support-annotations:23.2.0'
}
protobuf {
+17
View File
@@ -105,6 +105,7 @@ import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.dynamicui.ExtractedColors;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.logging.LoggerUtils;
@@ -279,6 +280,7 @@ public class Launcher extends Activity
private LauncherModel mModel;
private IconCache mIconCache;
private ExtractedColors mExtractedColors;
@Thunk boolean mUserPresent = true;
private boolean mVisible = false;
private boolean mHasFocus = false;
@@ -447,6 +449,8 @@ public class Launcher extends Activity
app.getInvariantDeviceProfile().portraitProfile.setSearchBarHeight(getSearchBarHeight());
setupViews();
mDeviceProfile.layout(this);
mExtractedColors = new ExtractedColors();
loadExtractedColorsAndColorItems();
lockAllApps();
@@ -509,6 +513,19 @@ public class Launcher extends Activity
}
}
@Override
public void onExtractedColorsChanged() {
loadExtractedColorsAndColorItems();
}
private void loadExtractedColorsAndColorItems() {
if (mExtractedColors != null) {
mExtractedColors.load(this);
// TODO: pass mExtractedColors to interested items such as hotseat.
mHotseat.setBackgroundColor(mExtractedColors.getColor(ExtractedColors.VIBRANT_INDEX));
}
}
private LauncherCallbacks mLauncherCallbacks;
public void onPostCreate(Bundle savedInstanceState) {
@@ -28,6 +28,7 @@ import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dynamicui.ExtractionUtils;
import com.android.launcher3.util.ConfigMonitor;
import com.android.launcher3.util.TestingUtils;
import com.android.launcher3.util.Thunk;
@@ -108,6 +109,11 @@ public class LauncherAppState {
filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED);
filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED);
filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
// For extracting colors from the wallpaper
if (Utilities.isNycOrAbove()) {
// TODO: add a broadcast entry to the manifest for pre-N.
filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
}
sContext.registerReceiver(mModel, filter);
UserManagerCompat.getInstance(sContext).enableAndResetCache();
@@ -121,6 +127,8 @@ public class LauncherAppState {
}, new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED));
}
new ConfigMonitor(sContext).register();
ExtractionUtils.startColorExtractionServiceIfNecessary(sContext);
}
/**
@@ -54,6 +54,7 @@ import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.dynamicui.ExtractionUtils;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.model.GridSizeMigrationTask;
@@ -1237,6 +1238,8 @@ public class LauncherModel extends BroadcastReceiver
PackageUpdatedTask.OP_USER_AVAILABILITY_CHANGE,
new String[0], user));
}
} else if (Intent.ACTION_WALLPAPER_CHANGED.equals(action)) {
ExtractionUtils.startColorExtractionServiceIfNecessary(context);
}
}
@@ -53,6 +53,7 @@ import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.dynamicui.ExtractionUtils;
import com.android.launcher3.util.ManagedProfileHeuristic;
import com.android.launcher3.util.NoLocaleSqliteContext;
import com.android.launcher3.util.Thunk;
@@ -257,7 +258,7 @@ public class LauncherProvider extends ContentProvider {
}
@Override
public Bundle call(String method, String arg, Bundle extras) {
public Bundle call(String method, final String arg, final Bundle extras) {
if (Binder.getCallingUid() != Process.myUid()) {
return null;
}
@@ -277,13 +278,19 @@ public class LauncherProvider extends ContentProvider {
return result;
}
case LauncherSettings.Settings.METHOD_SET_BOOLEAN: {
boolean value = extras.getBoolean(LauncherSettings.Settings.EXTRA_VALUE);
final boolean value = extras.getBoolean(LauncherSettings.Settings.EXTRA_VALUE);
Utilities.getPrefs(getContext()).edit().putBoolean(arg, value).apply();
synchronized (LISTENER_LOCK) {
if (mListener != null) {
mListener.onSettingsChanged(arg, value);
new MainThreadExecutor().execute(new Runnable() {
@Override
public void run() {
synchronized (LISTENER_LOCK) {
if (mListener != null) {
mListener.onSettingsChanged(arg, value);
}
}
}
}
});
if (extras.getBoolean(LauncherSettings.Settings.NOTIFY_BACKUP)) {
LauncherBackupAgentHelper.dataChanged(getContext());
}
@@ -291,6 +298,29 @@ public class LauncherProvider extends ContentProvider {
result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE, value);
return result;
}
case LauncherSettings.Settings.METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID: {
String extractedColors = extras.getString(
LauncherSettings.Settings.EXTRA_EXTRACTED_COLORS);
int wallpaperId = extras.getInt(LauncherSettings.Settings.EXTRA_WALLPAPER_ID);
Utilities.getPrefs(getContext()).edit()
.putString(ExtractionUtils.EXTRACTED_COLORS_PREFERENCE_KEY, extractedColors)
.putInt(ExtractionUtils.WALLPAPER_ID_PREFERENCE_KEY, wallpaperId)
.apply();
new MainThreadExecutor().execute(new Runnable() {
@Override
public void run() {
synchronized (LISTENER_LOCK) {
if (mListener != null) {
mListener.onExtractedColorsChanged();
}
}
}
});
Bundle result = new Bundle();
result.putString(LauncherSettings.Settings.EXTRA_VALUE, extractedColors);
return result;
}
case LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG: {
clearFlagEmptyDbCreated();
return null;
@@ -11,5 +11,7 @@ public interface LauncherProviderChangeListener {
public void onSettingsChanged(String settings, boolean value);
public void onExtractedColorsChanged();
public void onAppWidgetHostReset();
}
@@ -339,6 +339,11 @@ public class LauncherSettings {
public static final String METHOD_LOAD_DEFAULT_FAVORITES = "load_default_favorites";
public static final String METHOD_MIGRATE_LAUNCHER2_SHORTCUTS = "migrate_l2_shortcuts";
public static final String METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID =
"set_extracted_colors_and_wallpaper_id_setting";
public static final String EXTRA_EXTRACTED_COLORS = "extra_extractedColors";
public static final String EXTRA_WALLPAPER_ID = "extra_wallpaperId";
public static final String EXTRA_VALUE = "value";
public static final String EXTRA_DEFAULT_VALUE = "default_value";
// Extra for set_boolean method to also notify the backup manager of the change.
+4
View File
@@ -19,6 +19,7 @@ package com.android.launcher3;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.SearchManager;
import android.app.WallpaperManager;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ActivityNotFoundException;
@@ -63,10 +64,13 @@ import android.widget.Toast;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.dynamicui.ColorExtractionService;
import com.android.launcher3.util.IconNormalizer;
import com.android.wallpaperpicker.common.WallpaperManagerCompat;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Locale;
@@ -0,0 +1,63 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.dynamicui;
import android.app.IntentService;
import android.app.WallpaperManager;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.support.v7.graphics.Palette;
import com.android.launcher3.LauncherProvider;
import com.android.launcher3.LauncherSettings;
/**
* Extracts colors from the wallpaper, and saves results to {@link LauncherProvider}.
*/
public class ColorExtractionService extends IntentService {
public ColorExtractionService() {
super("ColorExtractionService");
}
@Override
protected void onHandleIntent(Intent intent) {
WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
int wallpaperId = ExtractionUtils.getWallpaperId(wallpaperManager);
ExtractedColors extractedColors = new ExtractedColors();
if (wallpaperManager.getWallpaperInfo() != null) {
// We can't extract colors from live wallpapers, so just use the default color always.
extractedColors.updatePalette(null);
} else {
Bitmap wallpaper = ((BitmapDrawable) wallpaperManager.getDrawable()).getBitmap();
Palette palette = Palette.from(wallpaper).generate();
extractedColors.updatePalette(palette);
}
// Save the extracted colors and wallpaper id to LauncherProvider.
String colorsString = extractedColors.encodeAsString();
Bundle extras = new Bundle();
extras.putInt(LauncherSettings.Settings.EXTRA_WALLPAPER_ID, wallpaperId);
extras.putString(LauncherSettings.Settings.EXTRA_EXTRACTED_COLORS, colorsString);
getContentResolver().call(
LauncherSettings.Settings.CONTENT_URI,
LauncherSettings.Settings.METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID,
null, extras);
}
}
@@ -0,0 +1,131 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.dynamicui;
import android.content.Context;
import android.graphics.Color;
import android.support.v7.graphics.Palette;
import android.util.Log;
import com.android.launcher3.Utilities;
/**
* Saves and loads colors extracted from the wallpaper, as well as the associated wallpaper id.
*/
public class ExtractedColors {
private static final String TAG = "ExtractedColors";
public static final int DEFAULT_LIGHT = Color.WHITE;
public static final int DEFAULT_DARK = Color.BLACK;
public static final int DEFAULT_COLOR = DEFAULT_LIGHT;
// These color profile indices should NOT be changed, since they are used when saving and
// loading extracted colors. New colors should always be added at the end.
public static final int DEFAULT_INDEX = 0;
public static final int VIBRANT_INDEX = 1;
public static final int VIBRANT_DARK_INDEX = 2;
public static final int VIBRANT_LIGHT_INDEX = 3;
public static final int MUTED_INDEX = 4;
public static final int MUTED_DARK_INDEX = 5;
public static final int MUTED_LIGHT_INDEX = 6;
public static final int NUM_COLOR_PROFILES = 7;
private static final String COLOR_SEPARATOR = ",";
private int[] mColors;
public ExtractedColors() {
mColors = new int[NUM_COLOR_PROFILES];
}
public void setColorAtIndex(int index, int color) {
if (index >= 0 && index < mColors.length) {
mColors[index] = color;
} else {
Log.e(TAG, "Attempted to set a color at an invalid index " + index);
}
}
/**
* Encodes {@link #mColors} as a comma-separated String.
*/
String encodeAsString() {
StringBuilder colorsStringBuilder = new StringBuilder();
for (int color : mColors) {
colorsStringBuilder.append(color).append(COLOR_SEPARATOR);
}
return colorsStringBuilder.toString();
}
/**
* Decodes a comma-separated String into {@link #mColors}.
*/
void decodeFromString(String colorsString) {
String[] splitColorsString = colorsString.split(COLOR_SEPARATOR);
mColors = new int[splitColorsString.length];
for (int i = 0; i < mColors.length; i++) {
mColors[i] = Integer.parseInt(splitColorsString[i]);
}
}
/**
* Loads colors and wallpaper id from {@link Utilities#getPrefs(Context)}.
* These were saved there in {@link ColorExtractionService}.
*/
public void load(Context context) {
String encodedString = Utilities.getPrefs(context).getString(
ExtractionUtils.EXTRACTED_COLORS_PREFERENCE_KEY, DEFAULT_COLOR + "");
decodeFromString(encodedString);
}
/** @param index must be one of the index values defined at the top of this class. */
public int getColor(int index) {
if (index >= 0 && index < mColors.length) {
return mColors[index];
}
return DEFAULT_COLOR;
}
/**
* Updates colors based on the palette.
* If the palette is null, the default color is used in all cases.
*/
public void updatePalette(Palette palette) {
if (palette == null) {
for (int i = 0; i < NUM_COLOR_PROFILES; i++) {
setColorAtIndex(i, ExtractedColors.DEFAULT_COLOR);
}
} else {
setColorAtIndex(ExtractedColors.DEFAULT_INDEX,
ExtractedColors.DEFAULT_COLOR);
setColorAtIndex(ExtractedColors.VIBRANT_INDEX,
palette.getVibrantColor(ExtractedColors.DEFAULT_COLOR));
setColorAtIndex(ExtractedColors.VIBRANT_DARK_INDEX,
palette.getDarkVibrantColor(ExtractedColors.DEFAULT_DARK));
setColorAtIndex(ExtractedColors.VIBRANT_LIGHT_INDEX,
palette.getLightVibrantColor(ExtractedColors.DEFAULT_LIGHT));
setColorAtIndex(ExtractedColors.MUTED_INDEX,
palette.getMutedColor(ExtractedColors.DEFAULT_COLOR));
setColorAtIndex(ExtractedColors.MUTED_DARK_INDEX,
palette.getDarkMutedColor(ExtractedColors.DEFAULT_DARK));
setColorAtIndex(ExtractedColors.MUTED_LIGHT_INDEX,
palette.getLightVibrantColor(ExtractedColors.DEFAULT_LIGHT));
}
}
}
@@ -0,0 +1,75 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.dynamicui;
import android.app.WallpaperManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import com.android.launcher3.Utilities;
import com.android.wallpaperpicker.common.WallpaperManagerCompat;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Contains helper fields and methods related to extracting colors from the wallpaper.
*/
public class ExtractionUtils {
public static final String EXTRACTED_COLORS_PREFERENCE_KEY = "pref_extractedColors";
public static final String WALLPAPER_ID_PREFERENCE_KEY = "pref_wallpaperId";
/**
* Extract colors in the :wallpaper-chooser process, if the wallpaper id has changed.
* When the new colors are saved in the LauncherProvider,
* Launcher will be notified in Launcher#onSettingsChanged(String, String).
*/
public static void startColorExtractionServiceIfNecessary(final Context context) {
// Run on a background thread, since the service is asynchronous anyway.
Utilities.THREAD_POOL_EXECUTOR.execute(new Runnable() {
@Override
public void run() {
if (hasWallpaperIdChanged(context)) {
context.startService(new Intent(context, ColorExtractionService.class));
}
}
});
}
private static boolean hasWallpaperIdChanged(Context context) {
if (!Utilities.isNycOrAbove()) {
// TODO: update an id in sharedprefs in onWallpaperChanged broadcast, and read it here.
return false;
}
final SharedPreferences sharedPrefs = Utilities.getPrefs(context);
int wallpaperId = getWallpaperId(WallpaperManager.getInstance(context));
int savedWallpaperId = sharedPrefs.getInt(ExtractionUtils.WALLPAPER_ID_PREFERENCE_KEY, -1);
return wallpaperId != savedWallpaperId;
}
public static int getWallpaperId(WallpaperManager wallpaperManager) {
// TODO: use WallpaperManager#getWallpaperId(WallpaperManager.FLAG_SET_SYSTEM) directly.
try {
Method getWallpaperId = WallpaperManager.class.getMethod("getWallpaperId", int.class);
return (int) getWallpaperId.invoke(wallpaperManager,
WallpaperManagerCompat.FLAG_SET_SYSTEM);
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
return -1;
}
}
}