am 80e6beb4: Ensure that layers are properly removed after animation
* commit '80e6beb48ca71a321f667e79fe35a7ab2fb4c2bf':
Ensure that layers are properly removed after animation
diff --git a/Android.mk b/Android.mk
index 110117b..632dd09 100644
--- a/Android.mk
+++ b/Android.mk
@@ -23,8 +23,6 @@
LOCAL_MODULE_TAGS := optional
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13
-
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-java-files-under, WallpaperPicker/src) \
$(call all-renderscript-files-under, src) \
diff --git a/WallpaperPicker/AndroidManifest.xml b/WallpaperPicker/AndroidManifest.xml
index 5b6a007..cb1457b 100644
--- a/WallpaperPicker/AndroidManifest.xml
+++ b/WallpaperPicker/AndroidManifest.xml
@@ -4,7 +4,7 @@
android:versionCode="1"
android:versionName="1.0"
>
-
- <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="19" />
+
+ <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />
<application/>
</manifest>
diff --git a/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java b/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java
index a671ed2..6a816d9 100644
--- a/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java
+++ b/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java
@@ -18,17 +18,13 @@
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
-import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
-import android.os.Build;
import android.util.FloatMath;
import android.util.Log;
import java.io.ByteArrayOutputStream;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
public class BitmapUtils {
private static final String TAG = "BitmapUtils";
@@ -187,54 +183,6 @@
return bitmap;
}
- public static Bitmap createVideoThumbnail(String filePath) {
- // MediaMetadataRetriever is available on API Level 8
- // but is hidden until API Level 10
- Class<?> clazz = null;
- Object instance = null;
- try {
- clazz = Class.forName("android.media.MediaMetadataRetriever");
- instance = clazz.newInstance();
-
- Method method = clazz.getMethod("setDataSource", String.class);
- method.invoke(instance, filePath);
-
- // The method name changes between API Level 9 and 10.
- if (Build.VERSION.SDK_INT <= 9) {
- return (Bitmap) clazz.getMethod("captureFrame").invoke(instance);
- } else {
- byte[] data = (byte[]) clazz.getMethod("getEmbeddedPicture").invoke(instance);
- if (data != null) {
- Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
- if (bitmap != null) return bitmap;
- }
- return (Bitmap) clazz.getMethod("getFrameAtTime").invoke(instance);
- }
- } catch (IllegalArgumentException ex) {
- // Assume this is a corrupt video file
- } catch (RuntimeException ex) {
- // Assume this is a corrupt video file.
- } catch (InstantiationException e) {
- Log.e(TAG, "createVideoThumbnail", e);
- } catch (InvocationTargetException e) {
- Log.e(TAG, "createVideoThumbnail", e);
- } catch (ClassNotFoundException e) {
- Log.e(TAG, "createVideoThumbnail", e);
- } catch (NoSuchMethodException e) {
- Log.e(TAG, "createVideoThumbnail", e);
- } catch (IllegalAccessException e) {
- Log.e(TAG, "createVideoThumbnail", e);
- } finally {
- try {
- if (instance != null) {
- clazz.getMethod("release").invoke(instance);
- }
- } catch (Exception ignored) {
- }
- }
- return null;
- }
-
public static byte[] compressToBytes(Bitmap bitmap) {
return compressToBytes(bitmap, DEFAULT_JPEG_QUALITY);
}
diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
index 09e0963..043f630 100644
--- a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
+++ b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
@@ -500,10 +500,9 @@
if (lastPhoto != null) {
ImageView galleryThumbnailBg =
(ImageView) pickImageTile.findViewById(R.id.wallpaper_image);
- galleryThumbnailBg.setImageBitmap(getThumbnailOfLastPhoto());
+ galleryThumbnailBg.setImageBitmap(lastPhoto);
int colorOverlay = getResources().getColor(R.color.wallpaper_picker_translucent_gray);
galleryThumbnailBg.setColorFilter(colorOverlay, PorterDuff.Mode.SRC_ATOP);
-
}
PickImageInfo pickImageInfo = new PickImageInfo();
diff --git a/WallpaperPicker/src/com/android/photos/views/BlockingGLTextureView.java b/WallpaperPicker/src/com/android/photos/views/BlockingGLTextureView.java
deleted file mode 100644
index 8a05051..0000000
--- a/WallpaperPicker/src/com/android/photos/views/BlockingGLTextureView.java
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Copyright (C) 2013 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.photos.views;
-
-import android.content.Context;
-import android.graphics.SurfaceTexture;
-import android.opengl.GLSurfaceView.Renderer;
-import android.opengl.GLUtils;
-import android.util.Log;
-import android.view.TextureView;
-import android.view.TextureView.SurfaceTextureListener;
-
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-import javax.microedition.khronos.egl.EGLSurface;
-import javax.microedition.khronos.opengles.GL10;
-
-/**
- * A TextureView that supports blocking rendering for synchronous drawing
- */
-public class BlockingGLTextureView extends TextureView
- implements SurfaceTextureListener {
-
- private RenderThread mRenderThread;
-
- public BlockingGLTextureView(Context context) {
- super(context);
- setSurfaceTextureListener(this);
- }
-
- public void setRenderer(Renderer renderer) {
- if (mRenderThread != null) {
- throw new IllegalArgumentException("Renderer already set");
- }
- mRenderThread = new RenderThread(renderer);
- }
-
- public void render() {
- mRenderThread.render();
- }
-
- public void destroy() {
- if (mRenderThread != null) {
- mRenderThread.finish();
- mRenderThread = null;
- }
- }
-
- @Override
- public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
- int height) {
- mRenderThread.setSurface(surface);
- mRenderThread.setSize(width, height);
- }
-
- @Override
- public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,
- int height) {
- mRenderThread.setSize(width, height);
- }
-
- @Override
- public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
- if (mRenderThread != null) {
- mRenderThread.setSurface(null);
- }
- return false;
- }
-
- @Override
- public void onSurfaceTextureUpdated(SurfaceTexture surface) {
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- destroy();
- } catch (Throwable t) {
- // Ignore
- }
- super.finalize();
- }
-
- /**
- * An EGL helper class.
- */
-
- private static class EglHelper {
- private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
- private static final int EGL_OPENGL_ES2_BIT = 4;
-
- EGL10 mEgl;
- EGLDisplay mEglDisplay;
- EGLSurface mEglSurface;
- EGLConfig mEglConfig;
- EGLContext mEglContext;
-
- private EGLConfig chooseEglConfig() {
- int[] configsCount = new int[1];
- EGLConfig[] configs = new EGLConfig[1];
- int[] configSpec = getConfig();
- if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
- throw new IllegalArgumentException("eglChooseConfig failed " +
- GLUtils.getEGLErrorString(mEgl.eglGetError()));
- } else if (configsCount[0] > 0) {
- return configs[0];
- }
- return null;
- }
-
- private static int[] getConfig() {
- return new int[] {
- EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL10.EGL_RED_SIZE, 8,
- EGL10.EGL_GREEN_SIZE, 8,
- EGL10.EGL_BLUE_SIZE, 8,
- EGL10.EGL_ALPHA_SIZE, 8,
- EGL10.EGL_DEPTH_SIZE, 0,
- EGL10.EGL_STENCIL_SIZE, 0,
- EGL10.EGL_NONE
- };
- }
-
- EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
- int[] attribList = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
- return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attribList);
- }
-
- /**
- * Initialize EGL for a given configuration spec.
- */
- public void start() {
- /*
- * Get an EGL instance
- */
- mEgl = (EGL10) EGLContext.getEGL();
-
- /*
- * Get to the default display.
- */
- mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
-
- if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
- throw new RuntimeException("eglGetDisplay failed");
- }
-
- /*
- * We can now initialize EGL for that display
- */
- int[] version = new int[2];
- if (!mEgl.eglInitialize(mEglDisplay, version)) {
- throw new RuntimeException("eglInitialize failed");
- }
- mEglConfig = chooseEglConfig();
-
- /*
- * Create an EGL context. We want to do this as rarely as we can, because an
- * EGL context is a somewhat heavy object.
- */
- mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
-
- if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
- mEglContext = null;
- throwEglException("createContext");
- }
-
- mEglSurface = null;
- }
-
- /**
- * Create an egl surface for the current SurfaceTexture surface. If a surface
- * already exists, destroy it before creating the new surface.
- *
- * @return true if the surface was created successfully.
- */
- public boolean createSurface(SurfaceTexture surface) {
- /*
- * Check preconditions.
- */
- if (mEgl == null) {
- throw new RuntimeException("egl not initialized");
- }
- if (mEglDisplay == null) {
- throw new RuntimeException("eglDisplay not initialized");
- }
- if (mEglConfig == null) {
- throw new RuntimeException("mEglConfig not initialized");
- }
-
- /*
- * The window size has changed, so we need to create a new
- * surface.
- */
- destroySurfaceImp();
-
- /*
- * Create an EGL surface we can render into.
- */
- if (surface != null) {
- mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surface, null);
- } else {
- mEglSurface = null;
- }
-
- if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
- int error = mEgl.eglGetError();
- if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
- Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
- }
- return false;
- }
-
- /*
- * Before we can issue GL commands, we need to make sure
- * the context is current and bound to a surface.
- */
- if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
- /*
- * Could not make the context current, probably because the underlying
- * SurfaceView surface has been destroyed.
- */
- logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
- return false;
- }
-
- return true;
- }
-
- /**
- * Create a GL object for the current EGL context.
- */
- public GL10 createGL() {
- return (GL10) mEglContext.getGL();
- }
-
- /**
- * Display the current render surface.
- * @return the EGL error code from eglSwapBuffers.
- */
- public int swap() {
- if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
- return mEgl.eglGetError();
- }
- return EGL10.EGL_SUCCESS;
- }
-
- public void destroySurface() {
- destroySurfaceImp();
- }
-
- private void destroySurfaceImp() {
- if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
- mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
- EGL10.EGL_NO_SURFACE,
- EGL10.EGL_NO_CONTEXT);
- mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
- mEglSurface = null;
- }
- }
-
- public void finish() {
- if (mEglContext != null) {
- mEgl.eglDestroyContext(mEglDisplay, mEglContext);
- mEglContext = null;
- }
- if (mEglDisplay != null) {
- mEgl.eglTerminate(mEglDisplay);
- mEglDisplay = null;
- }
- }
-
- private void throwEglException(String function) {
- throwEglException(function, mEgl.eglGetError());
- }
-
- public static void throwEglException(String function, int error) {
- String message = formatEglError(function, error);
- throw new RuntimeException(message);
- }
-
- public static void logEglErrorAsWarning(String tag, String function, int error) {
- Log.w(tag, formatEglError(function, error));
- }
-
- public static String formatEglError(String function, int error) {
- return function + " failed: " + error;
- }
-
- }
-
- private static class RenderThread extends Thread {
- private static final int INVALID = -1;
- private static final int RENDER = 1;
- private static final int CHANGE_SURFACE = 2;
- private static final int RESIZE_SURFACE = 3;
- private static final int FINISH = 4;
-
- private EglHelper mEglHelper = new EglHelper();
-
- private Object mLock = new Object();
- private int mExecMsgId = INVALID;
- private SurfaceTexture mSurface;
- private Renderer mRenderer;
- private int mWidth, mHeight;
-
- private boolean mFinished = false;
- private GL10 mGL;
-
- public RenderThread(Renderer renderer) {
- super("RenderThread");
- mRenderer = renderer;
- start();
- }
-
- private void checkRenderer() {
- if (mRenderer == null) {
- throw new IllegalArgumentException("Renderer is null!");
- }
- }
-
- private void checkSurface() {
- if (mSurface == null) {
- throw new IllegalArgumentException("surface is null!");
- }
- }
-
- public void setSurface(SurfaceTexture surface) {
- // If the surface is null we're being torn down, don't need a
- // renderer then
- if (surface != null) {
- checkRenderer();
- }
- mSurface = surface;
- exec(CHANGE_SURFACE);
- }
-
- public void setSize(int width, int height) {
- checkRenderer();
- checkSurface();
- mWidth = width;
- mHeight = height;
- exec(RESIZE_SURFACE);
- }
-
- public void render() {
- checkRenderer();
- if (mSurface != null) {
- exec(RENDER);
- mSurface.updateTexImage();
- }
- }
-
- public void finish() {
- mSurface = null;
- exec(FINISH);
- try {
- join();
- } catch (InterruptedException e) {
- // Ignore
- }
- }
-
- private void exec(int msgid) {
- synchronized (mLock) {
- if (mExecMsgId != INVALID) {
- throw new IllegalArgumentException(
- "Message already set - multithreaded access?");
- }
- mExecMsgId = msgid;
- mLock.notify();
- try {
- mLock.wait();
- } catch (InterruptedException e) {
- // Ignore
- }
- }
- }
-
- private void handleMessageLocked(int what) {
- switch (what) {
- case CHANGE_SURFACE:
- if (mEglHelper.createSurface(mSurface)) {
- mGL = mEglHelper.createGL();
- mRenderer.onSurfaceCreated(mGL, mEglHelper.mEglConfig);
- }
- break;
- case RESIZE_SURFACE:
- mRenderer.onSurfaceChanged(mGL, mWidth, mHeight);
- break;
- case RENDER:
- mRenderer.onDrawFrame(mGL);
- mEglHelper.swap();
- break;
- case FINISH:
- mEglHelper.destroySurface();
- mEglHelper.finish();
- mFinished = true;
- break;
- }
- }
-
- @Override
- public void run() {
- synchronized (mLock) {
- mEglHelper.start();
- while (!mFinished) {
- while (mExecMsgId == INVALID) {
- try {
- mLock.wait();
- } catch (InterruptedException e) {
- // Ignore
- }
- }
- handleMessageLocked(mExecMsgId);
- mExecMsgId = INVALID;
- mLock.notify();
- }
- mExecMsgId = FINISH;
- }
- }
- }
-}
diff --git a/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java b/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java
index c4e493b..b0292e6 100644
--- a/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java
+++ b/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java
@@ -20,9 +20,9 @@
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.support.v4.util.LongSparseArray;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.LongSparseArray;
import android.util.Pools.Pool;
import android.util.Pools.SynchronizedPool;
import android.view.View;
diff --git a/WallpaperPicker/src/com/android/photos/views/TiledImageView.java b/WallpaperPicker/src/com/android/photos/views/TiledImageView.java
index 94063b0..524fa2e 100644
--- a/WallpaperPicker/src/com/android/photos/views/TiledImageView.java
+++ b/WallpaperPicker/src/com/android/photos/views/TiledImageView.java
@@ -16,8 +16,6 @@
package com.android.photos.views;
-import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -28,11 +26,9 @@
import android.graphics.RectF;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
-import android.os.Build;
import android.util.AttributeSet;
import android.view.Choreographer;
import android.view.Choreographer.FrameCallback;
-import android.view.View;
import android.widget.FrameLayout;
import com.android.gallery3d.glrenderer.BasicTexture;
@@ -43,18 +39,10 @@
import javax.microedition.khronos.opengles.GL10;
/**
- * Shows an image using {@link TiledImageRenderer} using either {@link GLSurfaceView}
- * or {@link BlockingGLTextureView}.
+ * Shows an image using {@link TiledImageRenderer} using either {@link GLSurfaceView}.
*/
public class TiledImageView extends FrameLayout {
- private static final boolean USE_TEXTURE_VIEW = false;
- private static final boolean IS_SUPPORTED =
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
- private static final boolean USE_CHOREOGRAPHER =
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
-
- private BlockingGLTextureView mTextureView;
private GLSurfaceView mGLSurfaceView;
private boolean mInvalPending = false;
private FrameCallback mFrameCallback;
@@ -79,35 +67,19 @@
protected Object mLock = new Object();
protected ImageRendererWrapper mRenderer;
- public static boolean isTilingSupported() {
- return IS_SUPPORTED;
- }
-
public TiledImageView(Context context) {
this(context, null);
}
public TiledImageView(Context context, AttributeSet attrs) {
super(context, attrs);
- if (!IS_SUPPORTED) {
- return;
- }
-
mRenderer = new ImageRendererWrapper();
mRenderer.image = new TiledImageRenderer(this);
- View view;
- if (USE_TEXTURE_VIEW) {
- mTextureView = new BlockingGLTextureView(context);
- mTextureView.setRenderer(new TileRenderer());
- view = mTextureView;
- } else {
- mGLSurfaceView = new GLSurfaceView(context);
- mGLSurfaceView.setEGLContextClientVersion(2);
- mGLSurfaceView.setRenderer(new TileRenderer());
- mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
- view = mGLSurfaceView;
- }
- addView(view, new LayoutParams(
+ mGLSurfaceView = new GLSurfaceView(context);
+ mGLSurfaceView.setEGLContextClientVersion(2);
+ mGLSurfaceView.setRenderer(new TileRenderer());
+ mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+ addView(mGLSurfaceView, new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
//setTileSource(new ColoredTiles());
}
@@ -117,22 +89,11 @@
super.setVisibility(visibility);
// need to update inner view's visibility because it seems like we're causing it to draw
// from {@link #dispatchDraw} or {@link #invalidate} even if we are invisible.
- if (USE_TEXTURE_VIEW) {
- mTextureView.setVisibility(visibility);
- } else {
- mGLSurfaceView.setVisibility(visibility);
- }
+ mGLSurfaceView.setVisibility(visibility);
}
public void destroy() {
- if (!IS_SUPPORTED) {
- return;
- }
- if (USE_TEXTURE_VIEW) {
- mTextureView.destroy();
- } else {
- mGLSurfaceView.queueEvent(mFreeTextures);
- }
+ mGLSurfaceView.queueEvent(mFreeTextures);
}
private Runnable mFreeTextures = new Runnable() {
@@ -144,27 +105,14 @@
};
public void onPause() {
- if (!IS_SUPPORTED) {
- return;
- }
- if (!USE_TEXTURE_VIEW) {
- mGLSurfaceView.onPause();
- }
+ mGLSurfaceView.onPause();
}
public void onResume() {
- if (!IS_SUPPORTED) {
- return;
- }
- if (!USE_TEXTURE_VIEW) {
- mGLSurfaceView.onResume();
- }
+ mGLSurfaceView.onResume();
}
public void setTileSource(TileSource source, Runnable isReadyCallback) {
- if (!IS_SUPPORTED) {
- return;
- }
synchronized (mLock) {
mRenderer.source = source;
mRenderer.isReadyCallback = isReadyCallback;
@@ -181,9 +129,6 @@
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
- if (!IS_SUPPORTED) {
- return;
- }
synchronized (mLock) {
updateScaleIfNecessaryLocked(mRenderer);
}
@@ -200,43 +145,10 @@
}
@Override
- protected void dispatchDraw(Canvas canvas) {
- if (!IS_SUPPORTED) {
- return;
- }
- if (USE_TEXTURE_VIEW) {
- mTextureView.render();
- }
- super.dispatchDraw(canvas);
- }
-
- @SuppressLint("NewApi")
- @Override
- public void setTranslationX(float translationX) {
- if (!IS_SUPPORTED) {
- return;
- }
- super.setTranslationX(translationX);
- }
-
- @Override
public void invalidate() {
- if (!IS_SUPPORTED) {
- return;
- }
- if (USE_TEXTURE_VIEW) {
- super.invalidate();
- mTextureView.invalidate();
- } else {
- if (USE_CHOREOGRAPHER) {
- invalOnVsync();
- } else {
- mGLSurfaceView.requestRender();
- }
- }
+ invalOnVsync();
}
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void invalOnVsync() {
if (!mInvalPending) {
mInvalPending = true;
@@ -255,9 +167,6 @@
private RectF mTempRectF = new RectF();
public void positionFromMatrix(Matrix matrix) {
- if (!IS_SUPPORTED) {
- return;
- }
if (mRenderer.source != null) {
final int rotation = mRenderer.source.getRotation();
final boolean swap = !(rotation % 180 == 0);
diff --git a/protos/backup.proto b/protos/backup.proto
index 44c4b09..09330ee 100644
--- a/protos/backup.proto
+++ b/protos/backup.proto
@@ -72,6 +72,17 @@
}
message Favorite {
+ // Type of the app, this target represents
+ enum TargetType {
+ TARGET_NONE = 0;
+ TARGET_PHONE = 1;
+ TARGET_MESSENGER = 2;
+ TARGET_EMAIL = 3;
+ TARGET_BROWSER = 4;
+ TARGET_GALLERY = 5;
+ TARGET_CAMERA = 6;
+ }
+
required int64 id = 1;
required int32 itemType = 2;
optional string title = 3;
@@ -90,6 +101,7 @@
optional string iconPackage = 16;
optional string iconResource = 17;
optional bytes icon = 18;
+ optional TargetType targetType = 19 [default = TARGET_NONE];
}
message Screen {
diff --git a/res/xml/app_target_browser.xml b/res/xml/app_target_browser.xml
new file mode 100644
index 0000000..d7c3ed5
--- /dev/null
+++ b/res/xml/app_target_browser.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+ <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_BROWSER;end" />
+ <favorite launcher:uri="http://www.example.com/" />
+
+</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_camera.xml b/res/xml/app_target_camera.xml
new file mode 100644
index 0000000..f65a2b1
--- /dev/null
+++ b/res/xml/app_target_camera.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+ <favorite launcher:uri="#Intent;action=android.media.action.STILL_IMAGE_CAMERA;end" />
+ <favorite launcher:uri="#Intent;action=android.intent.action.CAMERA_BUTTON;end" />
+
+</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_email.xml b/res/xml/app_target_email.xml
new file mode 100644
index 0000000..44f0a40
--- /dev/null
+++ b/res/xml/app_target_email.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+ <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_EMAIL;end" />
+ <favorite launcher:uri="mailto:" />
+
+</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_gallery.xml b/res/xml/app_target_gallery.xml
new file mode 100644
index 0000000..c9d3492
--- /dev/null
+++ b/res/xml/app_target_gallery.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+ <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_GALLERY;end" />
+ <favorite launcher:uri="#Intent;type=images/*;end" />
+
+</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_messenger.xml b/res/xml/app_target_messenger.xml
new file mode 100644
index 0000000..278eb5c
--- /dev/null
+++ b/res/xml/app_target_messenger.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+ <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MESSAGING;end" />
+ <favorite launcher:uri="sms:" />
+ <favorite launcher:uri="smsto:" />
+ <favorite launcher:uri="mms:" />
+ <favorite launcher:uri="mmsto:" />
+
+</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_phone.xml b/res/xml/app_target_phone.xml
new file mode 100644
index 0000000..5d6ca31
--- /dev/null
+++ b/res/xml/app_target_phone.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+ <favorite launcher:uri="#Intent;action=android.intent.action.DIAL;end" />
+ <favorite launcher:uri="tel:123" />
+ <favorite launcher:uri="#Intent;action=android.intent.action.CALL_BUTTON;end" />
+
+</resolve>
\ No newline at end of file
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 3820660..908bd3d 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -116,7 +116,7 @@
private final Context mContext;
private final AppWidgetHost mAppWidgetHost;
- private final LayoutParserCallback mCallback;
+ protected final LayoutParserCallback mCallback;
protected final PackageManager mPackageManager;
protected final Resources mSourceRes;
@@ -126,13 +126,20 @@
private final long[] mTemp = new long[2];
private final ContentValues mValues;
- private final String mRootTag;
+ protected final String mRootTag;
protected SQLiteDatabase mDb;
public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
LayoutParserCallback callback, Resources res,
int layoutId, String rootTag) {
+ this(context, appWidgetHost, callback, res, layoutId, rootTag,
+ LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile().hotseatAllAppsRank);
+ }
+
+ public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
+ LayoutParserCallback callback, Resources res,
+ int layoutId, String rootTag, int hotseatAllAppsRank) {
mContext = context;
mAppWidgetHost = appWidgetHost;
mCallback = callback;
@@ -143,8 +150,7 @@
mSourceRes = res;
mLayoutId = layoutId;
- mHotseatAllAppsRank = LauncherAppState.getInstance()
- .getDynamicGrid().getDeviceProfile().hotseatAllAppsRank;
+ mHotseatAllAppsRank = hotseatAllAppsRank;
}
/**
diff --git a/src/com/android/launcher3/CommonAppTypeParser.java b/src/com/android/launcher3/CommonAppTypeParser.java
new file mode 100644
index 0000000..fe2fbd7
--- /dev/null
+++ b/src/com/android/launcher3/CommonAppTypeParser.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2008 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;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.XmlResourceParser;
+import android.database.sqlite.SQLiteDatabase;
+import android.util.Log;
+
+import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.backup.BackupProtos.Favorite;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * A class that parses content values corresponding to some common app types.
+ */
+public class CommonAppTypeParser implements LayoutParserCallback {
+ private static final String TAG = "CommonAppTypeParser";
+
+ // Including TARGET_NONE
+ public static final int SUPPORTED_TYPE_COUNT = 7;
+
+ private static final int RESTORE_FLAG_BIT_SHIFT = 4;
+
+
+ private final long mItemId;
+ private final int mResId;
+ private final Context mContext;
+
+ ContentValues parsedValues;
+ Intent parsedIntent;
+ String parsedTitle;
+
+ public CommonAppTypeParser(long itemId, int itemType, Context context) {
+ mItemId = itemId;
+ mContext = context;
+ mResId = getResourceForItemType(itemType);
+ }
+
+ @Override
+ public long generateNewItemId() {
+ return mItemId;
+ }
+
+ @Override
+ public long insertAndCheck(SQLiteDatabase db, ContentValues values) {
+ parsedValues = values;
+
+ // Remove unwanted values
+ values.put(Favorites.ICON_TYPE, (Integer) null);
+ values.put(Favorites.ICON_PACKAGE, (String) null);
+ values.put(Favorites.ICON_RESOURCE, (String) null);
+ values.put(Favorites.ICON, (byte[]) null);
+ return 1;
+ }
+
+ /**
+ * Tries to find a suitable app to the provided app type.
+ */
+ public boolean findDefaultApp() {
+ if (mResId == 0) {
+ return false;
+ }
+
+ parsedIntent = null;
+ parsedValues = null;
+ new MyLayoutParser().parseValues();
+ return (parsedValues != null) && (parsedIntent != null);
+ }
+
+ private class MyLayoutParser extends DefaultLayoutParser {
+
+ public MyLayoutParser() {
+ super(mContext, null, CommonAppTypeParser.this,
+ mContext.getResources(), mResId, TAG_RESOLVE, 0);
+ }
+
+ @Override
+ protected long addShortcut(String title, Intent intent, int type) {
+ if (type == Favorites.ITEM_TYPE_APPLICATION) {
+ parsedIntent = intent;
+ parsedTitle = title;
+ }
+ return super.addShortcut(title, intent, type);
+ }
+
+ public void parseValues() {
+ XmlResourceParser parser = mSourceRes.getXml(mLayoutId);
+ try {
+ beginDocument(parser, mRootTag);
+ new ResolveParser().parseAndAdd(parser);
+ } catch (IOException | XmlPullParserException e) {
+ Log.e(TAG, "Unable to parse default app info", e);
+ }
+ parser.close();
+ }
+ }
+
+ public static int getResourceForItemType(int type) {
+ switch (type) {
+ case Favorite.TARGET_PHONE:
+ return R.xml.app_target_phone;
+
+ case Favorite.TARGET_MESSENGER:
+ return R.xml.app_target_messenger;
+
+ case Favorite.TARGET_EMAIL:
+ return R.xml.app_target_email;
+
+ case Favorite.TARGET_BROWSER:
+ return R.xml.app_target_browser;
+
+ case Favorite.TARGET_GALLERY:
+ return R.xml.app_target_gallery;
+
+ case Favorite.TARGET_CAMERA:
+ return R.xml.app_target_camera;
+
+ default:
+ return 0;
+ }
+ }
+
+ public static int encodeItemTypeToFlag(int itemType) {
+ return itemType << RESTORE_FLAG_BIT_SHIFT;
+ }
+
+ public static int decodeItemTypeFromFlag(int flag) {
+ return (flag & ShortcutInfo.FLAG_RESTORED_APP_TYPE) >> RESTORE_FLAG_BIT_SHIFT;
+ }
+
+}
diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java
index 986ae81..6c3008b 100644
--- a/src/com/android/launcher3/DefaultLayoutParser.java
+++ b/src/com/android/launcher3/DefaultLayoutParser.java
@@ -28,15 +28,15 @@
public class DefaultLayoutParser extends AutoInstallsLayout {
private static final String TAG = "DefaultLayoutParser";
- private static final String TAG_RESOLVE = "resolve";
+ protected static final String TAG_RESOLVE = "resolve";
private static final String TAG_FAVORITES = "favorites";
- private static final String TAG_FAVORITE = "favorite";
+ protected static final String TAG_FAVORITE = "favorite";
private static final String TAG_APPWIDGET = "appwidget";
private static final String TAG_SHORTCUT = "shortcut";
private static final String TAG_FOLDER = "folder";
private static final String TAG_PARTNER_FOLDER = "partner-folder";
- private static final String ATTR_URI = "uri";
+ protected static final String ATTR_URI = "uri";
private static final String ATTR_CONTAINER = "container";
private static final String ATTR_SCREEN = "screen";
private static final String ATTR_FOLDER_ITEMS = "folderItems";
@@ -44,7 +44,12 @@
public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost,
LayoutParserCallback callback, Resources sourceRes, int layoutId) {
super(context, appWidgetHost, callback, sourceRes, layoutId, TAG_FAVORITES);
- Log.e(TAG, "Default layout parser initialized");
+ }
+
+ public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost,
+ LayoutParserCallback callback, Resources sourceRes, int layoutId, String rootTag,
+ int hotseatAllAppsRank) {
+ super(context, appWidgetHost, callback, sourceRes, layoutId, rootTag, hotseatAllAppsRank);
}
@Override
@@ -196,7 +201,7 @@
/**
* Contains a list of <favorite> nodes, and accepts the first successfully parsed node.
*/
- private class ResolveParser implements TagParser {
+ protected class ResolveParser implements TagParser {
private final AppShortcutWithUriParser mChildParser = new AppShortcutWithUriParser();
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 66b6568..6925477 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -21,12 +21,13 @@
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
+import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.Build;
import android.os.SystemClock;
-import android.support.v4.widget.AutoScrollHelper;
import android.text.InputType;
import android.text.Selection;
import android.text.Spannable;
@@ -123,8 +124,6 @@
private boolean mDestroyed;
- private AutoScrollHelper mAutoScrollHelper;
-
private Runnable mDeferredAction;
private boolean mDeferDropAfterUninstall;
private boolean mUninstallSuccessful;
@@ -208,7 +207,6 @@
mFolderName.setSelectAllOnFocus(true);
mFolderName.setInputType(mFolderName.getInputType() |
InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
- mAutoScrollHelper = new FolderAutoScrollHelper(mScrollView);
}
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
@@ -700,6 +698,7 @@
}
}
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public boolean isLayoutRtl() {
return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
}
@@ -715,29 +714,19 @@
final MotionEvent translatedEv = MotionEvent.obtain(
downTime, downTime, MotionEvent.ACTION_MOVE, d.x, d.y, 0);
- if (!mAutoScrollHelper.isEnabled()) {
- mAutoScrollHelper.setEnabled(true);
- }
-
- final boolean handled = mAutoScrollHelper.onTouch(this, translatedEv);
translatedEv.recycle();
-
- if (handled) {
+ mTargetCell = mContent.findNearestArea(
+ (int) r[0], (int) r[1] + scrollOffset, 1, 1, mTargetCell);
+ if (isLayoutRtl()) {
+ mTargetCell[0] = mContent.getCountX() - mTargetCell[0] - 1;
+ }
+ if (mTargetCell[0] != mPreviousTargetCell[0]
+ || mTargetCell[1] != mPreviousTargetCell[1]) {
mReorderAlarm.cancelAlarm();
- } else {
- mTargetCell = mContent.findNearestArea(
- (int) r[0], (int) r[1] + scrollOffset, 1, 1, mTargetCell);
- if (isLayoutRtl()) {
- mTargetCell[0] = mContent.getCountX() - mTargetCell[0] - 1;
- }
- if (mTargetCell[0] != mPreviousTargetCell[0]
- || mTargetCell[1] != mPreviousTargetCell[1]) {
- mReorderAlarm.cancelAlarm();
- mReorderAlarm.setOnAlarmListener(mReorderAlarmListener);
- mReorderAlarm.setAlarm(REORDER_DELAY);
- mPreviousTargetCell[0] = mTargetCell[0];
- mPreviousTargetCell[1] = mTargetCell[1];
- }
+ mReorderAlarm.setOnAlarmListener(mReorderAlarmListener);
+ mReorderAlarm.setAlarm(REORDER_DELAY);
+ mPreviousTargetCell[0] = mTargetCell[0];
+ mPreviousTargetCell[1] = mTargetCell[1];
}
}
@@ -783,8 +772,6 @@
}
public void onDragExit(DragObject d) {
- // Exiting folder; stop the auto scroller.
- mAutoScrollHelper.setEnabled(false);
// We only close the folder if this is a true drag exit, ie. not because
// a drop has occurred above the folder.
if (!d.dragComplete) {
diff --git a/src/com/android/launcher3/FolderAutoScrollHelper.java b/src/com/android/launcher3/FolderAutoScrollHelper.java
deleted file mode 100644
index 40e8884..0000000
--- a/src/com/android/launcher3/FolderAutoScrollHelper.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2013 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;
-
-import android.support.v4.widget.AutoScrollHelper;
-import android.widget.ScrollView;
-
-/**
- * An implementation of {@link AutoScrollHelper} that knows how to scroll
- * through a {@link Folder}.
- */
-public class FolderAutoScrollHelper extends AutoScrollHelper {
- private static final float MAX_SCROLL_VELOCITY = 1500f;
-
- private final ScrollView mTarget;
-
- public FolderAutoScrollHelper(ScrollView target) {
- super(target);
-
- mTarget = target;
-
- setActivationDelay(0);
- setEdgeType(EDGE_TYPE_INSIDE_EXTEND);
- setExclusive(true);
- setMaximumVelocity(MAX_SCROLL_VELOCITY, MAX_SCROLL_VELOCITY);
- setRampDownDuration(0);
- setRampUpDuration(0);
- }
-
- @Override
- public void scrollTargetBy(int deltaX, int deltaY) {
- mTarget.scrollBy(deltaX, deltaY);
- }
-
- @Override
- public boolean canTargetScrollHorizontally(int direction) {
- // List do not scroll horizontally.
- return false;
- }
-
- @Override
- public boolean canTargetScrollVertically(int direction) {
- return mTarget.canScrollVertically(direction);
- }
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index b08272f..289b08b 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -16,14 +16,12 @@
package com.android.launcher3;
-import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -33,7 +31,6 @@
import java.util.ArrayList;
public class Hotseat extends FrameLayout {
- private static final String TAG = "Hotseat";
private CellLayout mContent;
@@ -182,38 +179,6 @@
return false;
}
- void addAllAppsFolder(IconCache iconCache,
- ArrayList<AppInfo> allApps, ArrayList<ComponentName> onWorkspace,
- Launcher launcher, Workspace workspace) {
- if (LauncherAppState.isDisableAllApps()) {
- FolderInfo fi = new FolderInfo();
-
- fi.cellX = getCellXFromOrder(mAllAppsButtonRank);
- fi.cellY = getCellYFromOrder(mAllAppsButtonRank);
- fi.spanX = 1;
- fi.spanY = 1;
- fi.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT;
- fi.screenId = mAllAppsButtonRank;
- fi.itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
- fi.title = "More Apps";
- LauncherModel.addItemToDatabase(launcher, fi, fi.container, fi.screenId, fi.cellX,
- fi.cellY, false);
- FolderIcon folder = FolderIcon.fromXml(R.layout.folder_icon, launcher,
- getLayout(), fi, iconCache);
- workspace.addInScreen(folder, fi.container, fi.screenId, fi.cellX, fi.cellY,
- fi.spanX, fi.spanY);
-
- for (AppInfo info: allApps) {
- ComponentName cn = info.intent.getComponent();
- if (!onWorkspace.contains(cn)) {
- Log.d(TAG, "Adding to 'more apps': " + info.intent);
- ShortcutInfo si = info.makeShortcut();
- fi.add(si);
- }
- }
- }
- }
-
void addAppsToAllAppsFolder(ArrayList<AppInfo> apps) {
if (LauncherAppState.isDisableAllApps()) {
View v = mContent.getChildAt(getCellXFromOrder(mAllAppsButtonRank), getCellYFromOrder(mAllAppsButtonRank));
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index eb2b5b8..7e2ae4e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -115,9 +115,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collection;
@@ -230,8 +227,6 @@
private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500;
private static final int ACTIVITY_START_DELAY = 1000;
- private static final Object sLock = new Object();
-
private HashMap<Integer, Integer> mItemIdToViewId = new HashMap<Integer, Integer>();
private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
@@ -341,8 +336,6 @@
// it from the context.
private SharedPreferences mSharedPrefs;
- private static ArrayList<ComponentName> mIntentsOnWorkspaceFromUpgradePath = null;
-
// Holds the page that we need to animate to, and the icon views that we need to animate up
// when we scroll to that page on resume.
private ImageView mFolderIconImageView;
@@ -1689,40 +1682,19 @@
* Sets up transparent navigation and status bars in LMP.
* This method is a no-op for other platform versions.
*/
- @TargetApi(19)
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setupTransparentSystemBarsForLmp() {
- // TODO(sansid): use the APIs directly when compiling against L sdk.
- // Currently we use reflection to access the flags and the API to set the transparency
- // on the System bars.
if (Utilities.isLmpOrAbove()) {
- try {
- getWindow().getAttributes().systemUiVisibility |=
- (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
- | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
- Field drawsSysBackgroundsField = WindowManager.LayoutParams.class.getField(
- "FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS");
- getWindow().addFlags(drawsSysBackgroundsField.getInt(null));
-
- Method setStatusBarColorMethod =
- Window.class.getDeclaredMethod("setStatusBarColor", int.class);
- Method setNavigationBarColorMethod =
- Window.class.getDeclaredMethod("setNavigationBarColor", int.class);
- setStatusBarColorMethod.invoke(getWindow(), Color.TRANSPARENT);
- setNavigationBarColorMethod.invoke(getWindow(), Color.TRANSPARENT);
- } catch (NoSuchFieldException e) {
- Log.w(TAG, "NoSuchFieldException while setting up transparent bars");
- } catch (NoSuchMethodException ex) {
- Log.w(TAG, "NoSuchMethodException while setting up transparent bars");
- } catch (IllegalAccessException e) {
- Log.w(TAG, "IllegalAccessException while setting up transparent bars");
- } catch (IllegalArgumentException e) {
- Log.w(TAG, "IllegalArgumentException while setting up transparent bars");
- } catch (InvocationTargetException e) {
- Log.w(TAG, "InvocationTargetException while setting up transparent bars");
- } finally {}
+ Window window = getWindow();
+ window.getAttributes().systemUiVisibility |=
+ (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+ window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
+ | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ window.setStatusBarColor(Color.TRANSPARENT);
+ window.setNavigationBarColor(Color.TRANSPARENT);
}
}
@@ -4487,10 +4459,10 @@
*
* Implementation of the method from LauncherModel.Callbacks.
*/
- public void finishBindingItems(final boolean upgradePath) {
+ public void finishBindingItems() {
Runnable r = new Runnable() {
public void run() {
- finishBindingItems(upgradePath);
+ finishBindingItems();
}
};
if (waitUntilResume(r)) {
@@ -4525,14 +4497,10 @@
sPendingAddItem = null;
}
- if (upgradePath) {
- mWorkspace.getUniqueComponents(true, null);
- mIntentsOnWorkspaceFromUpgradePath = mWorkspace.getUniqueComponents(true, null);
- }
PackageInstallerCompat.getInstance(this).onFinishBind();
if (mLauncherCallbacks != null) {
- mLauncherCallbacks.finishBindingItems(upgradePath);
+ mLauncherCallbacks.finishBindingItems(false);
}
}
@@ -4599,13 +4567,6 @@
*/
public void bindAllApplications(final ArrayList<AppInfo> apps) {
if (LauncherAppState.isDisableAllApps()) {
- if (mIntentsOnWorkspaceFromUpgradePath != null) {
- if (LauncherModel.UPGRADE_USE_MORE_APPS_FOLDER) {
- getHotseat().addAllAppsFolder(mIconCache, apps,
- mIntentsOnWorkspaceFromUpgradePath, Launcher.this, mWorkspace);
- }
- mIntentsOnWorkspaceFromUpgradePath = null;
- }
if (mAppsCustomizeContent != null) {
mAppsCustomizeContent.onPackagesUpdated(
LauncherModel.getSortedWidgetsAndShortcuts(this));
@@ -4815,8 +4776,12 @@
public void lockScreenOrientation() {
if (Utilities.isRotationEnabled(this)) {
- setRequestedOrientation(mapConfigurationOriActivityInfoOri(getResources()
- .getConfiguration().orientation));
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ setRequestedOrientation(mapConfigurationOriActivityInfoOri(getResources()
+ .getConfiguration().orientation));
+ } else {
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
+ }
}
}
public void unlockScreenOrientation(boolean immediate) {
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java
index 32bea5b..353bf3f 100644
--- a/src/com/android/launcher3/LauncherBackupHelper.java
+++ b/src/com/android/launcher3/LauncherBackupHelper.java
@@ -19,13 +19,16 @@
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupHelper;
import android.app.backup.BackupManager;
-import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -51,6 +54,9 @@
import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
import com.google.protobuf.nano.MessageNano;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -58,7 +64,6 @@
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.zip.CRC32;
@@ -138,6 +143,7 @@
private final Context mContext;
private final HashSet<String> mExistingKeys;
private final ArrayList<Key> mKeys;
+ private final ItemTypeMatcher[] mItemTypeMatchers;
private IconCache mIconCache;
private BackupManager mBackupManager;
@@ -154,6 +160,7 @@
mExistingKeys = new HashSet<String>();
mKeys = new ArrayList<Key>();
restoreSuccessful = true;
+ mItemTypeMatchers = new ItemTypeMatcher[CommonAppTypeParser.SUPPORTED_TYPE_COUNT];
}
private void dataChanged() {
@@ -753,6 +760,17 @@
return checksum.getValue();
}
+ /**
+ * @return true if its an hotseat item, that can be replaced during restore.
+ * TODO: Extend check for folders in hotseat.
+ */
+ private boolean isReplaceableHotseatItem(Favorite favorite) {
+ return favorite.container == Favorites.CONTAINER_HOTSEAT
+ && favorite.intent != null
+ && (favorite.itemType == Favorites.ITEM_TYPE_APPLICATION
+ || favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT);
+ }
+
/** Serialize a Favorite for persistence, including a checksum wrapper. */
private Favorite packFavorite(Cursor c) {
Favorite favorite = new Favorite();
@@ -785,9 +803,10 @@
favorite.title = title;
}
String intentDescription = c.getString(INTENT_INDEX);
+ Intent intent = null;
if (!TextUtils.isEmpty(intentDescription)) {
try {
- Intent intent = Intent.parseUri(intentDescription, 0);
+ intent = Intent.parseUri(intentDescription, 0);
intent.removeExtra(ItemInfo.EXTRA_PROFILE);
favorite.intent = intent.toUri(0);
} catch (URISyntaxException e) {
@@ -803,6 +822,31 @@
}
}
+ if (isReplaceableHotseatItem(favorite)) {
+ if (intent != null && intent.getComponent() != null) {
+ PackageManager pm = mContext.getPackageManager();
+ ActivityInfo activity = null;;
+ try {
+ activity = pm.getActivityInfo(intent.getComponent(), 0);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Target not found", e);
+ }
+ if (activity == null) {
+ return favorite;
+ }
+ for (int i = 0; i < mItemTypeMatchers.length; i++) {
+ if (mItemTypeMatchers[i] == null) {
+ mItemTypeMatchers[i] = new ItemTypeMatcher(
+ CommonAppTypeParser.getResourceForItemType(i));
+ }
+ if (mItemTypeMatchers[i].matches(activity, pm)) {
+ favorite.targetType = i;
+ break;
+ }
+ }
+ }
+ }
+
return favorite;
}
@@ -810,6 +854,7 @@
private ContentValues unpackFavorite(byte[] buffer, int dataSize)
throws IOException {
Favorite favorite = unpackProto(new Favorite(), buffer, dataSize);
+
ContentValues values = new ContentValues();
values.put(Favorites._ID, favorite.id);
values.put(Favorites.SCREEN, favorite.screen);
@@ -860,8 +905,17 @@
throw new InvalidBackupException("Widget not in screen bounds, aborting restore");
}
} else {
- // Let LauncherModel know we've been here.
- values.put(LauncherSettings.Favorites.RESTORED, 1);
+ // Check if it is an hotseat item, that can be replaced.
+ if (isReplaceableHotseatItem(favorite)
+ && favorite.targetType != Favorite.TARGET_NONE
+ && favorite.targetType < CommonAppTypeParser.SUPPORTED_TYPE_COUNT) {
+ Log.e(TAG, "Added item type flag");
+ values.put(LauncherSettings.Favorites.RESTORED,
+ 1 | CommonAppTypeParser.encodeItemTypeToFlag(favorite.targetType));
+ } else {
+ // Let LauncherModel know we've been here.
+ values.put(LauncherSettings.Favorites.RESTORED, 1);
+ }
// Verify placement
if (favorite.container == Favorites.CONTAINER_HOTSEAT) {
@@ -1128,6 +1182,9 @@
}
private class InvalidBackupException extends IOException {
+
+ private static final long serialVersionUID = 8931456637211665082L;
+
private InvalidBackupException(Throwable cause) {
super(cause);
}
@@ -1136,4 +1193,54 @@
super(reason);
}
}
+
+ /**
+ * A class to check if an activity can handle one of the intents from a list of
+ * predefined intents.
+ */
+ private class ItemTypeMatcher {
+
+ private final ArrayList<Intent> mIntents;
+
+ ItemTypeMatcher(int xml_res) {
+ mIntents = xml_res == 0 ? new ArrayList<Intent>() : parseIntents(xml_res);
+ }
+
+ private ArrayList<Intent> parseIntents(int xml_res) {
+ ArrayList<Intent> intents = new ArrayList<Intent>();
+ XmlResourceParser parser = mContext.getResources().getXml(xml_res);
+ try {
+ DefaultLayoutParser.beginDocument(parser, DefaultLayoutParser.TAG_RESOLVE);
+ final int depth = parser.getDepth();
+ int type;
+ while (((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ } else if (DefaultLayoutParser.TAG_FAVORITE.equals(parser.getName())) {
+ final String uri = DefaultLayoutParser.getAttributeValue(
+ parser, DefaultLayoutParser.ATTR_URI);
+ intents.add(Intent.parseUri(uri, 0));
+ }
+ }
+ } catch (URISyntaxException | XmlPullParserException | IOException e) {
+ Log.e(TAG, "Unable to parse " + xml_res, e);
+ } finally {
+ parser.close();
+ }
+ return intents;
+ }
+
+ public boolean matches(ActivityInfo activity, PackageManager pm) {
+ for (Intent intent : mIntents) {
+ intent.setPackage(activity.packageName);
+ ResolveInfo info = pm.resolveActivity(intent, 0);
+ if (info != null && (info.activityInfo.name.equals(activity.name)
+ || info.activityInfo.name.equals(activity.targetActivity))) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 9f97631..3983835 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -75,7 +75,6 @@
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.TreeMap;
/**
* Maintains in-memory state of the Launcher. It is expected that there should be only one
@@ -91,9 +90,6 @@
static final String TAG = "Launcher.Model";
- // true = use a "More Apps" folder for non-workspace apps on upgrade
- // false = strew non-workspace apps across the workspace on upgrade
- public static final boolean UPGRADE_USE_MORE_APPS_FOLDER = false;
public static final int LOADER_FLAG_NONE = 0;
public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;
public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;
@@ -199,7 +195,7 @@
public void bindScreens(ArrayList<Long> orderedScreenIds);
public void bindAddScreens(ArrayList<Long> orderedScreenIds);
public void bindFolders(HashMap<Long,FolderInfo> folders);
- public void finishBindingItems(boolean upgradePath);
+ public void finishBindingItems();
public void bindAppWidget(LauncherAppWidgetInfo info);
public void bindAllApplications(ArrayList<AppInfo> apps);
public void bindAppsAdded(ArrayList<Long> newScreens,
@@ -491,13 +487,7 @@
Runnable r = new Runnable() {
public void run() {
final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();
-
- ArrayList<Long> workspaceScreens = new ArrayList<Long>();
- TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);
- for (Integer i : orderedScreens.keySet()) {
- long screenId = orderedScreens.get(i);
- workspaceScreens.add(screenId);
- }
+ ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);
// Find appropriate space for the item.
Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,
@@ -549,13 +539,7 @@
// Get the list of workspace screens. We need to append to this list and
// can not use sBgWorkspaceScreens because loadWorkspace() may not have been
// called.
- ArrayList<Long> workspaceScreens = new ArrayList<Long>();
- TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);
- for (Integer i : orderedScreens.keySet()) {
- long screenId = orderedScreens.get(i);
- workspaceScreens.add(screenId);
- }
-
+ ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);
synchronized(sBgLock) {
for (ItemInfo item : workspaceApps) {
if (!allowDuplicate) {
@@ -1443,40 +1427,31 @@
}
}
- /** Loads the workspace screens db into a map of Rank -> ScreenId */
- private static TreeMap<Integer, Long> loadWorkspaceScreensDb(Context context) {
+ /**
+ * Loads the workspace screen ids in an ordered list.
+ */
+ private static ArrayList<Long> loadWorkspaceScreensDb(Context context) {
final ContentResolver contentResolver = context.getContentResolver();
final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
- final Cursor sc = contentResolver.query(screensUri, null, null, null, null);
- TreeMap<Integer, Long> orderedScreens = new TreeMap<Integer, Long>();
+ // Get screens ordered by rank.
+ final Cursor sc = contentResolver.query(screensUri, null, null, null,
+ LauncherSettings.WorkspaceScreens.SCREEN_RANK);
+ ArrayList<Long> screenIds = new ArrayList<Long>();
try {
- final int idIndex = sc.getColumnIndexOrThrow(
- LauncherSettings.WorkspaceScreens._ID);
- final int rankIndex = sc.getColumnIndexOrThrow(
- LauncherSettings.WorkspaceScreens.SCREEN_RANK);
+ final int idIndex = sc.getColumnIndexOrThrow(LauncherSettings.WorkspaceScreens._ID);
while (sc.moveToNext()) {
try {
- long screenId = sc.getLong(idIndex);
- int rank = sc.getInt(rankIndex);
- orderedScreens.put(rank, screenId);
+ screenIds.add(sc.getLong(idIndex));
} catch (Exception e) {
- Launcher.addDumpLog(TAG, "Desktop items loading interrupted - invalid screens: " + e, true);
+ Launcher.addDumpLog(TAG, "Desktop items loading interrupted"
+ + " - invalid screens: " + e, true);
}
}
} finally {
sc.close();
}
-
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - loadWorkspaceScreensDb()", true);
- ArrayList<String> orderedScreensPairs= new ArrayList<String>();
- for (Integer i : orderedScreens.keySet()) {
- orderedScreensPairs.add("{ " + i + ": " + orderedScreens.get(i) + " }");
- }
- Launcher.addDumpLog(TAG, "11683562 - screens: " +
- TextUtils.join(", ", orderedScreensPairs), true);
- return orderedScreens;
+ return screenIds;
}
public boolean isAllAppsLoaded() {
@@ -1523,8 +1498,7 @@
return mIsLoadingAndBindingWorkspace;
}
- /** Returns whether this is an upgrade path */
- private boolean loadAndBindWorkspace() {
+ private void loadAndBindWorkspace() {
mIsLoadingAndBindingWorkspace = true;
// Load the workspace
@@ -1532,20 +1506,18 @@
Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);
}
- boolean isUpgradePath = false;
if (!mWorkspaceLoaded) {
- isUpgradePath = loadWorkspace();
+ loadWorkspace();
synchronized (LoaderTask.this) {
if (mStopped) {
- return isUpgradePath;
+ return;
}
mWorkspaceLoaded = true;
}
}
// Bind the workspace
- bindWorkspace(-1, isUpgradePath);
- return isUpgradePath;
+ bindWorkspace(-1);
}
private void waitForIdle() {
@@ -1614,15 +1586,13 @@
// Divide the set of loaded items into those that we are binding synchronously, and
// everything else that is to be bound normally (asynchronously).
- bindWorkspace(synchronousBindPage, false);
+ bindWorkspace(synchronousBindPage);
// XXX: For now, continue posting the binding of AllApps as there are other issues that
// arise from that.
onlyBindAllApps();
}
public void run() {
- boolean isUpgrade = false;
-
synchronized (mLock) {
mIsLoaderTaskRunning = true;
}
@@ -1639,7 +1609,7 @@
? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);
}
if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
- isUpgrade = loadAndBindWorkspace();
+ loadAndBindWorkspace();
if (mStopped) {
break keep_running;
@@ -1677,9 +1647,7 @@
if (LauncherAppState.isDisableAllApps()) {
// Ensure that all the applications that are in the system are
// represented on the home screen.
- if (!UPGRADE_USE_MORE_APPS_FOLDER || !isUpgrade) {
- verifyApplications();
- }
+ verifyApplications();
}
// Clear out this reference, otherwise we end up holding it until all of the
@@ -1856,8 +1824,7 @@
}
}
- /** Returns whether this is an upgrade path */
- private boolean loadWorkspace() {
+ private void loadWorkspace() {
// Log to disk
Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);
@@ -1891,12 +1858,6 @@
LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary();
}
- // This code path is for our old migration code and should no longer be exercised
- boolean loadedOldDb = false;
-
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - loadedOldDb: " + loadedOldDb, true);
-
synchronized (sBgLock) {
clearSBgDataStructures();
final HashSet<String> installingPkgs = PackageInstallerCompat
@@ -1977,6 +1938,7 @@
user = mUserManager.getUserForSerialNumber(serialNumber);
int promiseType = c.getInt(restoredIndex);
int disabledState = 0;
+ boolean itemReplaced = false;
if (user == null) {
// User has been deleted remove the item.
itemsToRemove.add(id);
@@ -2008,9 +1970,7 @@
ContentValues values = new ContentValues();
values.put(LauncherSettings.Favorites.INTENT,
intent.toUri(0));
- String where = BaseColumns._ID + "= ?";
- String[] args = {Long.toString(id)};
- contentResolver.update(contentUri, values, where, args);
+ updateItem(id, values);
}
}
@@ -2040,10 +2000,27 @@
ContentValues values = new ContentValues();
values.put(LauncherSettings.Favorites.RESTORED,
promiseType);
- String where = BaseColumns._ID + "= ?";
- String[] args = {Long.toString(id)};
- contentResolver.update(contentUri, values, where, args);
+ updateItem(id, values);
+ } else if ((promiseType & ShortcutInfo.FLAG_RESTORED_APP_TYPE) != 0) {
+ // This is a common app. Try to replace this.
+ int appType = CommonAppTypeParser.decodeItemTypeFromFlag(promiseType);
+ CommonAppTypeParser parser = new CommonAppTypeParser(id, appType, context);
+ if (parser.findDefaultApp()) {
+ // Default app found. Replace it.
+ intent = parser.parsedIntent;
+ cn = intent.getComponent();
+ ContentValues values = parser.parsedValues;
+ values.put(LauncherSettings.Favorites.RESTORED, 0);
+ updateItem(id, values);
+ restored = false;
+ itemReplaced = true;
+ } else if (REMOVE_UNRESTORED_ICONS) {
+ Launcher.addDumpLog(TAG,
+ "Unrestored package removed: " + cn, true);
+ itemsToRemove.add(id);
+ continue;
+ }
} else if (REMOVE_UNRESTORED_ICONS) {
Launcher.addDumpLog(TAG,
"Unrestored package removed: " + cn, true);
@@ -2089,7 +2066,16 @@
continue;
}
- if (restored) {
+ if (itemReplaced) {
+ if (user.equals(UserHandleCompat.myUserHandle())) {
+ info = getShortcutInfo(manager, intent, user, context, null,
+ iconIndex, titleIndex, mLabelCache, false);
+ } else {
+ // Don't replace items for other profiles.
+ itemsToRemove.add(id);
+ continue;
+ }
+ } else if (restored) {
if (user.equals(UserHandleCompat.myUserHandle())) {
Launcher.addDumpLog(TAG,
"constructing info for partially restored package",
@@ -2323,9 +2309,7 @@
providerName);
values.put(LauncherSettings.Favorites.RESTORED,
appWidgetInfo.restoreStatus);
- String where = BaseColumns._ID + "= ?";
- String[] args = {Long.toString(id)};
- contentResolver.update(contentUri, values, where, args);
+ updateItem(id, values);
}
}
sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);
@@ -2346,7 +2330,7 @@
// Break early if we've stopped loading
if (mStopped) {
clearSBgDataStructures();
- return false;
+ return;
}
if (itemsToRemove.size() > 0) {
@@ -2392,63 +2376,29 @@
null, sWorker);
}
- if (loadedOldDb) {
- long maxScreenId = 0;
- // If we're importing we use the old screen order.
- for (ItemInfo item: sBgItemsIdMap.values()) {
- long screenId = item.screenId;
- if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
- !sBgWorkspaceScreens.contains(screenId)) {
- sBgWorkspaceScreens.add(screenId);
- if (screenId > maxScreenId) {
- maxScreenId = screenId;
- }
- }
- }
- Collections.sort(sBgWorkspaceScreens);
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - maxScreenId: " + maxScreenId, true);
- Launcher.addDumpLog(TAG, "11683562 - sBgWorkspaceScreens: " +
- TextUtils.join(", ", sBgWorkspaceScreens), true);
+ sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext));
+ // Log to disk
+ Launcher.addDumpLog(TAG, "11683562 - sBgWorkspaceScreens: " +
+ TextUtils.join(", ", sBgWorkspaceScreens), true);
- LauncherAppState.getLauncherProvider().updateMaxScreenId(maxScreenId);
+ // Remove any empty screens
+ ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);
+ for (ItemInfo item: sBgItemsIdMap.values()) {
+ long screenId = item.screenId;
+ if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
+ unusedScreens.contains(screenId)) {
+ unusedScreens.remove(screenId);
+ }
+ }
+
+ // If there are any empty screens remove them, and update.
+ if (unusedScreens.size() != 0) {
+ // Log to disk
+ Launcher.addDumpLog(TAG, "11683562 - unusedScreens (to be removed): " +
+ TextUtils.join(", ", unusedScreens), true);
+
+ sBgWorkspaceScreens.removeAll(unusedScreens);
updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);
-
- // Update the max item id after we load an old db
- long maxItemId = 0;
- // If we're importing we use the old screen order.
- for (ItemInfo item: sBgItemsIdMap.values()) {
- maxItemId = Math.max(maxItemId, item.id);
- }
- LauncherAppState.getLauncherProvider().updateMaxItemId(maxItemId);
- } else {
- TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(mContext);
- for (Integer i : orderedScreens.keySet()) {
- sBgWorkspaceScreens.add(orderedScreens.get(i));
- }
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - sBgWorkspaceScreens: " +
- TextUtils.join(", ", sBgWorkspaceScreens), true);
-
- // Remove any empty screens
- ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);
- for (ItemInfo item: sBgItemsIdMap.values()) {
- long screenId = item.screenId;
- if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
- unusedScreens.contains(screenId)) {
- unusedScreens.remove(screenId);
- }
- }
-
- // If there are any empty screens remove them, and update.
- if (unusedScreens.size() != 0) {
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - unusedScreens (to be removed): " +
- TextUtils.join(", ", unusedScreens), true);
-
- sBgWorkspaceScreens.removeAll(unusedScreens);
- updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);
- }
}
if (DEBUG_LOADERS) {
@@ -2477,7 +2427,17 @@
}
}
}
- return loadedOldDb;
+ }
+
+ /**
+ * Partially updates the item without any notification. Must be called on the worker thread.
+ */
+ private void updateItem(long itemId, ContentValues update) {
+ mContext.getContentResolver().update(
+ LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,
+ update,
+ BaseColumns._ID + "= ?",
+ new String[]{Long.toString(itemId)});
}
/** Filters the set of items who are directly or indirectly (via another container) on the
@@ -2674,7 +2634,7 @@
/**
* Binds all loaded data to actual views on the main thread.
*/
- private void bindWorkspace(int synchronizeBindPage, final boolean isUpgradePath) {
+ private void bindWorkspace(int synchronizeBindPage) {
final long t = SystemClock.uptimeMillis();
Runnable r;
@@ -2778,7 +2738,7 @@
public void run() {
Callbacks callbacks = tryGetCallbacks(oldCallbacks);
if (callbacks != null) {
- callbacks.finishBindingItems(isUpgradePath);
+ callbacks.finishBindingItems();
}
// If we're profiling, ensure this is the last thing in the queue.
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 0088f26..ab1347b 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -57,7 +57,6 @@
private static final String TAG = "Launcher.LauncherProvider";
private static final boolean LOGD = false;
- private static final int MIN_DATABASE_VERSION = 12;
private static final int DATABASE_VERSION = 21;
static final String OLD_AUTHORITY = "com.android.launcher2.settings";
@@ -66,7 +65,6 @@
static final String TABLE_FAVORITES = "favorites";
static final String TABLE_WORKSPACE_SCREENS = "workspaceScreens";
static final String PARAMETER_NOTIFY = "notify";
- static final String UPGRADED_FROM_OLD_DATABASE = "UPGRADED_FROM_OLD_DATABASE";
static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED";
private static final String URI_PARAM_IS_EXTERNAL_ADD = "isExternalAdd";
@@ -251,12 +249,6 @@
return mOpenHelper.generateNewScreenId();
}
- // This is only required one time while loading the workspace during the
- // upgrade path, and should never be called from anywhere else.
- public void updateMaxScreenId(long maxScreenId) {
- mOpenHelper.updateMaxScreenId(maxScreenId);
- }
-
/**
* Clears all the data for a fresh start.
*/
@@ -474,135 +466,112 @@
private void setFlagJustLoadedOldDb() {
String spKey = LauncherAppState.getSharedPreferencesKey();
SharedPreferences sp = mContext.getSharedPreferences(spKey, Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sp.edit();
- editor.putBoolean(UPGRADED_FROM_OLD_DATABASE, true);
- editor.putBoolean(EMPTY_DATABASE_CREATED, false);
- editor.commit();
+ sp.edit().putBoolean(EMPTY_DATABASE_CREATED, false).commit();
}
private void setFlagEmptyDbCreated() {
String spKey = LauncherAppState.getSharedPreferencesKey();
SharedPreferences sp = mContext.getSharedPreferences(spKey, Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sp.edit();
- editor.putBoolean(EMPTY_DATABASE_CREATED, true);
- editor.putBoolean(UPGRADED_FROM_OLD_DATABASE, false);
- editor.commit();
+ sp.edit().putBoolean(EMPTY_DATABASE_CREATED, true).commit();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (LOGD) Log.d(TAG, "onUpgrade triggered: " + oldVersion);
-
- int version = oldVersion;
- if (version < MIN_DATABASE_VERSION) {
- // The version cannot be lower that this, as Launcher3 never supported a lower
+ switch (oldVersion) {
+ // The version cannot be lower that 12, as Launcher3 never supported a lower
// version of the DB.
- createEmptyDB(db);
- version = DATABASE_VERSION;
- }
-
- if (version < 13) {
- // With the new shrink-wrapped and re-orderable workspaces, it makes sense
- // to persist workspace screens and their relative order.
- mMaxScreenId = 0;
-
- addWorkspacesTable(db);
- version = 13;
- }
-
- if (version < 14) {
- db.beginTransaction();
- try {
- // Insert new column for holding widget provider name
- db.execSQL("ALTER TABLE favorites " +
- "ADD COLUMN appWidgetProvider TEXT;");
- db.setTransactionSuccessful();
- version = 14;
- } catch (SQLException ex) {
- // Old version remains, which means we wipe old data
- Log.e(TAG, ex.getMessage(), ex);
- } finally {
- db.endTransaction();
+ case 12: {
+ // With the new shrink-wrapped and re-orderable workspaces, it makes sense
+ // to persist workspace screens and their relative order.
+ mMaxScreenId = 0;
+ addWorkspacesTable(db);
+ }
+ case 13: {
+ db.beginTransaction();
+ try {
+ // Insert new column for holding widget provider name
+ db.execSQL("ALTER TABLE favorites " +
+ "ADD COLUMN appWidgetProvider TEXT;");
+ db.setTransactionSuccessful();
+ } catch (SQLException ex) {
+ Log.e(TAG, ex.getMessage(), ex);
+ // Old version remains, which means we wipe old data
+ break;
+ } finally {
+ db.endTransaction();
+ }
+ }
+ case 14: {
+ db.beginTransaction();
+ try {
+ // Insert new column for holding update timestamp
+ db.execSQL("ALTER TABLE favorites " +
+ "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
+ db.execSQL("ALTER TABLE workspaceScreens " +
+ "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
+ db.setTransactionSuccessful();
+ } catch (SQLException ex) {
+ Log.e(TAG, ex.getMessage(), ex);
+ // Old version remains, which means we wipe old data
+ break;
+ } finally {
+ db.endTransaction();
+ }
+ }
+ case 15: {
+ db.beginTransaction();
+ try {
+ // Insert new column for holding restore status
+ db.execSQL("ALTER TABLE favorites " +
+ "ADD COLUMN restored INTEGER NOT NULL DEFAULT 0;");
+ db.setTransactionSuccessful();
+ } catch (SQLException ex) {
+ Log.e(TAG, ex.getMessage(), ex);
+ // Old version remains, which means we wipe old data
+ break;
+ } finally {
+ db.endTransaction();
+ }
+ }
+ case 16: {
+ // We use the db version upgrade here to identify users who may not have seen
+ // clings yet (because they weren't available), but for whom the clings are now
+ // available (tablet users). Because one of the possible cling flows (migration)
+ // is very destructive (wipes out workspaces), we want to prevent this from showing
+ // until clear data. We do so by marking that the clings have been shown.
+ LauncherClings.synchonouslyMarkFirstRunClingDismissed(mContext);
+ }
+ case 17: {
+ // No-op
+ }
+ case 18: {
+ // Due to a data loss bug, some users may have items associated with screen ids
+ // which no longer exist. Since this can cause other problems, and since the user
+ // will never see these items anyway, we use database upgrade as an opportunity to
+ // clean things up.
+ removeOrphanedItems(db);
+ }
+ case 19: {
+ // Add userId column
+ if (!addProfileColumn(db)) {
+ // Old version remains, which means we wipe old data
+ break;
+ }
+ }
+ case 20:
+ if (!updateFolderItemsRank(db, true)) {
+ break;
+ }
+ case 21: {
+ // DB Upgraded successfully
+ return;
}
}
- if (version < 15) {
- db.beginTransaction();
- try {
- // Insert new column for holding update timestamp
- db.execSQL("ALTER TABLE favorites " +
- "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
- db.execSQL("ALTER TABLE workspaceScreens " +
- "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
- db.setTransactionSuccessful();
- version = 15;
- } catch (SQLException ex) {
- // Old version remains, which means we wipe old data
- Log.e(TAG, ex.getMessage(), ex);
- } finally {
- db.endTransaction();
- }
- }
-
-
- if (version < 16) {
- db.beginTransaction();
- try {
- // Insert new column for holding restore status
- db.execSQL("ALTER TABLE favorites " +
- "ADD COLUMN restored INTEGER NOT NULL DEFAULT 0;");
- db.setTransactionSuccessful();
- version = 16;
- } catch (SQLException ex) {
- // Old version remains, which means we wipe old data
- Log.e(TAG, ex.getMessage(), ex);
- } finally {
- db.endTransaction();
- }
- }
-
- if (version < 17) {
- // We use the db version upgrade here to identify users who may not have seen
- // clings yet (because they weren't available), but for whom the clings are now
- // available (tablet users). Because one of the possible cling flows (migration)
- // is very destructive (wipes out workspaces), we want to prevent this from showing
- // until clear data. We do so by marking that the clings have been shown.
- LauncherClings.synchonouslyMarkFirstRunClingDismissed(mContext);
- version = 17;
- }
-
- if (version < 18) {
- // No-op
- version = 18;
- }
-
- if (version < 19) {
- // Due to a data loss bug, some users may have items associated with screen ids
- // which no longer exist. Since this can cause other problems, and since the user
- // will never see these items anyway, we use database upgrade as an opportunity to
- // clean things up.
- removeOrphanedItems(db);
- version = 19;
- }
-
- if (version < 20) {
- // Add userId column
- if (addProfileColumn(db)) {
- version = 20;
- }
- // else old version remains, which means we wipe old data
- }
-
- if (version < 21) {
- if (updateFolderItemsRank(db, true)) {
- version = 21;
- }
- }
-
- if (version != DATABASE_VERSION) {
- Log.w(TAG, "Destroying all old data.");
- createEmptyDB(db);
- }
+ // DB was not upgraded
+ Log.w(TAG, "Destroying all old data.");
+ createEmptyDB(db);
}
@Override
@@ -745,12 +714,6 @@
return mMaxScreenId;
}
- public void updateMaxScreenId(long maxScreenId) {
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - updateMaxScreenId(): " + maxScreenId, true);
- mMaxScreenId = maxScreenId;
- }
-
private long initializeMaxScreenId(SQLiteDatabase db) {
Cursor c = db.rawQuery("SELECT MAX(" + LauncherSettings.WorkspaceScreens._ID + ") FROM " + TABLE_WORKSPACE_SCREENS, null);
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 01f7931..15d6a3e 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -46,18 +46,24 @@
* be present along with {@link #FLAG_RESTORED_ICON}, and is set during default layout
* parsing.
*/
- public static final int FLAG_AUTOINTALL_ICON = 2;
+ public static final int FLAG_AUTOINTALL_ICON = 2; //0B10;
/**
* The icon is being installed. If {@link FLAG_RESTORED_ICON} or {@link FLAG_AUTOINTALL_ICON}
* is set, then the icon is either being installed or is in a broken state.
*/
- public static final int FLAG_INSTALL_SESSION_ACTIVE = 4;
+ public static final int FLAG_INSTALL_SESSION_ACTIVE = 4; // 0B100;
/**
* Indicates that the widget restore has started.
*/
- public static final int FLAG_RESTORE_STARTED = 8;
+ public static final int FLAG_RESTORE_STARTED = 8; //0B1000;
+
+ /**
+ * Indicates if it represents a common type mentioned in {@link CommonAppTypeParser}.
+ * Upto 15 different types supported.
+ */
+ public static final int FLAG_RESTORED_APP_TYPE = 0B0011110000;
/**
* The intent used to start the application.
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 4021727..661c3ce 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -43,12 +43,10 @@
import android.graphics.Rect;
import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
-import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.IBinder;
import android.os.Parcelable;
-import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
@@ -492,7 +490,7 @@
CellLayout cl = ((CellLayout) child);
cl.setOnInterceptTouchListener(this);
cl.setClickable(true);
- cl.setImportantForAccessibility(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ cl.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
super.onChildViewAdded(parent, child);
}
@@ -561,10 +559,6 @@
}
public long insertNewWorkspaceScreen(long screenId, int insertIndex) {
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - insertNewWorkspaceScreen(): " + screenId +
- " at index: " + insertIndex, true);
-
if (mWorkspaceScreens.containsKey(screenId)) {
throw new RuntimeException("Screen id " + screenId + " already exists!");
}
@@ -664,9 +658,6 @@
}
public void addExtraEmptyScreenOnDrag() {
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - addExtraEmptyScreenOnDrag()", true);
-
boolean lastChildOnScreen = false;
boolean childOnFinalScreen = false;
@@ -693,9 +684,6 @@
}
public boolean addExtraEmptyScreen() {
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - addExtraEmptyScreen()", true);
-
if (!mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)) {
insertNewWorkspaceScreen(EXTRA_EMPTY_SCREEN_ID);
return true;
@@ -704,9 +692,6 @@
}
private void convertFinalScreenToEmptyScreenIfNecessary() {
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - convertFinalScreenToEmptyScreenIfNecessary()", true);
-
if (mLauncher.isWorkspaceLoading()) {
// Invalid and dangerous operation if workspace is loading
Launcher.addDumpLog(TAG, " - workspace loading, skip", true);
@@ -731,7 +716,6 @@
// Update the model if we have changed any screens
mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
- Launcher.addDumpLog(TAG, "11683562 - extra empty screen: " + finalScreenId, true);
}
}
@@ -741,8 +725,6 @@
public void removeExtraEmptyScreenDelayed(final boolean animate, final Runnable onComplete,
final int delay, final boolean stripEmptyScreens) {
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - removeExtraEmptyScreen()", true);
if (mLauncher.isWorkspaceLoading()) {
// Don't strip empty screens if the workspace is still loading
Launcher.addDumpLog(TAG, " - workspace loading, skip", true);
@@ -784,9 +766,7 @@
private void fadeAndRemoveEmptyScreen(int delay, int duration, final Runnable onComplete,
final boolean stripEmptyScreens) {
- // Log to disk
// XXX: Do we need to update LM workspace screens below?
- Launcher.addDumpLog(TAG, "11683562 - fadeAndRemoveEmptyScreen()", true);
PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0f);
PropertyValuesHolder bgAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", 0f);
@@ -830,8 +810,6 @@
}
public long commitExtraEmptyScreen() {
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - commitExtraEmptyScreen()", true);
if (mLauncher.isWorkspaceLoading()) {
// Invalid and dangerous operation if workspace is loading
Launcher.addDumpLog(TAG, " - workspace loading, skip", true);
@@ -890,9 +868,6 @@
}
public void stripEmptyScreens() {
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - stripEmptyScreens()", true);
-
if (mLauncher.isWorkspaceLoading()) {
// Don't strip empty screens if the workspace is still loading.
// This is dangerous and can result in data loss.
@@ -920,7 +895,6 @@
int pageShift = 0;
for (Long id: removeScreens) {
- Launcher.addDumpLog(TAG, "11683562 - removing id: " + id, true);
CellLayout cl = mWorkspaceScreens.get(id);
mWorkspaceScreens.remove(id);
mScreenOrder.remove(id);
@@ -2210,8 +2184,8 @@
private void updateAccessibilityFlags() {
int accessible = mState == State.NORMAL ?
- ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES :
- ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
+ IMPORTANT_FOR_ACCESSIBILITY_YES :
+ IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
setImportantForAccessibility(accessible);
}
@@ -4116,7 +4090,6 @@
// In the case where we've prebound the widget, we remove it from the DragLayer
if (finalView instanceof AppWidgetHostView && external) {
- Log.d(TAG, "6557954 Animate widget drop, final view is appWidgetHostView");
mLauncher.getDragLayer().removeView(finalView);
}
@@ -4307,88 +4280,6 @@
}
}
- ArrayList<ComponentName> getUniqueComponents(boolean stripDuplicates, ArrayList<ComponentName> duplicates) {
- ArrayList<ComponentName> uniqueIntents = new ArrayList<ComponentName>();
- getUniqueIntents((CellLayout) mLauncher.getHotseat().getLayout(), uniqueIntents, duplicates, false);
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- CellLayout cl = (CellLayout) getChildAt(i);
- getUniqueIntents(cl, uniqueIntents, duplicates, false);
- }
- return uniqueIntents;
- }
-
- void getUniqueIntents(CellLayout cl, ArrayList<ComponentName> uniqueIntents,
- ArrayList<ComponentName> duplicates, boolean stripDuplicates) {
- int count = cl.getShortcutsAndWidgets().getChildCount();
-
- ArrayList<View> children = new ArrayList<View>();
- for (int i = 0; i < count; i++) {
- View v = cl.getShortcutsAndWidgets().getChildAt(i);
- children.add(v);
- }
-
- for (int i = 0; i < count; i++) {
- View v = children.get(i);
- ItemInfo info = (ItemInfo) v.getTag();
- // Null check required as the AllApps button doesn't have an item info
- if (info instanceof ShortcutInfo) {
- ShortcutInfo si = (ShortcutInfo) info;
- ComponentName cn = si.intent.getComponent();
-
- Uri dataUri = si.intent.getData();
- // If dataUri is not null / empty or if this component isn't one that would
- // have previously showed up in the AllApps list, then this is a widget-type
- // shortcut, so ignore it.
- if (dataUri != null && !dataUri.equals(Uri.EMPTY)) {
- continue;
- }
-
- if (!uniqueIntents.contains(cn)) {
- uniqueIntents.add(cn);
- } else {
- if (stripDuplicates) {
- cl.removeViewInLayout(v);
- LauncherModel.deleteItemFromDatabase(mLauncher, si);
- }
- if (duplicates != null) {
- duplicates.add(cn);
- }
- }
- }
- if (v instanceof FolderIcon) {
- FolderIcon fi = (FolderIcon) v;
- ArrayList<View> items = fi.getFolder().getItemsInReadingOrder();
- for (int j = 0; j < items.size(); j++) {
- if (items.get(j).getTag() instanceof ShortcutInfo) {
- ShortcutInfo si = (ShortcutInfo) items.get(j).getTag();
- ComponentName cn = si.intent.getComponent();
-
- Uri dataUri = si.intent.getData();
- // If dataUri is not null / empty or if this component isn't one that would
- // have previously showed up in the AllApps list, then this is a widget-type
- // shortcut, so ignore it.
- if (dataUri != null && !dataUri.equals(Uri.EMPTY)) {
- continue;
- }
-
- if (!uniqueIntents.contains(cn)) {
- uniqueIntents.add(cn);
- } else {
- if (stripDuplicates) {
- fi.getFolderInfo().remove(si);
- LauncherModel.deleteItemFromDatabase(mLauncher, si);
- }
- if (duplicates != null) {
- duplicates.add(cn);
- }
- }
- }
- }
- }
- }
- }
-
void saveWorkspaceToDb() {
saveWorkspaceScreenToDb((CellLayout) mLauncher.getHotseat().getLayout());
int count = getChildCount();
diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java
index 1d41a6f..ea51aac 100644
--- a/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java
+++ b/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java
@@ -29,13 +29,15 @@
public class LauncherActivityInfoCompatV16 extends LauncherActivityInfoCompat {
- private ActivityInfo mActivityInfo;
- private ComponentName mComponentName;
- private PackageManager mPm;
+ private final ResolveInfo mResolveInfo;
+ private final ActivityInfo mActivityInfo;
+ private final ComponentName mComponentName;
+ private final PackageManager mPm;
LauncherActivityInfoCompatV16(Context context, ResolveInfo info) {
super();
- this.mActivityInfo = info.activityInfo;
+ mResolveInfo = info;
+ mActivityInfo = info.activityInfo;
mComponentName = new ComponentName(mActivityInfo.packageName, mActivityInfo.name);
mPm = context.getPackageManager();
}
@@ -49,31 +51,30 @@
}
public CharSequence getLabel() {
- return mActivityInfo.loadLabel(mPm);
+ return mResolveInfo.loadLabel(mPm);
}
public Drawable getIcon(int density) {
- Drawable d = null;
- if (mActivityInfo.getIconResource() != 0) {
- Resources resources;
+ int iconRes = mResolveInfo.getIconResource();
+ Resources resources = null;
+ Drawable icon = null;
+ // Get the preferred density icon from the app's resources
+ if (density != 0 && iconRes != 0) {
try {
- resources = mPm.getResourcesForApplication(mActivityInfo.packageName);
- } catch (PackageManager.NameNotFoundException e) {
- resources = null;
- }
- if (resources != null) {
- try {
- d = resources.getDrawableForDensity(mActivityInfo.getIconResource(), density);
- } catch (Resources.NotFoundException e) {
- // Return default icon below.
- }
+ resources = mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
+ icon = resources.getDrawableForDensity(iconRes, density);
+ } catch (NameNotFoundException | Resources.NotFoundException exc) {
}
}
- if (d == null) {
- Resources resources = Resources.getSystem();
- d = resources.getDrawableForDensity(android.R.mipmap.sym_def_app_icon, density);
+ // Get the default density icon
+ if (icon == null) {
+ icon = mResolveInfo.loadIcon(mPm);
}
- return d;
+ if (icon == null) {
+ resources = Resources.getSystem();
+ icon = resources.getDrawableForDensity(android.R.mipmap.sym_def_app_icon, density);
+ }
+ return icon;
}
public ApplicationInfo getApplicationInfo() {