summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3')
-rw-r--r--src/com/android/launcher3/ItemInfo.java9
-rw-r--r--src/com/android/launcher3/Launcher.java8
-rw-r--r--src/com/android/launcher3/Workspace.java122
-rw-r--r--src/com/android/launcher3/WorkspaceLayoutManager.java141
-rw-r--r--src/com/android/launcher3/folder/FolderPagedView.java6
-rw-r--r--src/com/android/launcher3/graphics/FragmentWithPreview.java48
-rw-r--r--src/com/android/launcher3/graphics/LauncherPreviewRenderer.java292
-rw-r--r--src/com/android/launcher3/qsb/QsbContainerView.java42
-rw-r--r--src/com/android/launcher3/util/MyActivity.java63
9 files changed, 590 insertions, 141 deletions
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index bffdd724b..a13060477 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -204,4 +204,13 @@ public class ItemInfo {
public boolean isDisabled() {
return false;
}
+
+ public int getViewId() {
+ // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
+ // This cast is safe as long as the id < 0x00FFFFFF
+ // Since we jail all the dynamically generated views, there should be no clashes
+ // with any other views.
+ return id;
+ }
+
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index ce6de2a2a..b4cc1ceff 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -460,14 +460,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
return !isWorkspaceLoading();
}
- public int getViewIdForItem(ItemInfo info) {
- // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
- // This cast is safe as long as the id < 0x00FFFFFF
- // Since we jail all the dynamically generated views, there should be no clashes
- // with any other views.
- return (int) info.id;
- }
-
public PopupDataProvider getPopupDataProvider() {
return mPopupDataProvider;
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 8a39b3b40..47ebb1795 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -79,7 +79,6 @@ import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.pageindicators.WorkspacePageIndicator;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
-import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.touch.WorkspaceTouchListener;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -107,8 +106,8 @@ import java.util.Set;
*/
public class Workspace extends PagedView<WorkspacePageIndicator>
implements DropTarget, DragSource, View.OnTouchListener,
- DragController.DragListener, Insettable, LauncherStateManager.StateHandler {
- private static final String TAG = "Launcher.Workspace";
+ DragController.DragListener, Insettable, LauncherStateManager.StateHandler,
+ WorkspaceLayoutManager {
/** The value that {@link #mTransitionProgress} must be greater than for
* {@link #transitionStateShouldAllowDrop()} to return true. */
@@ -130,11 +129,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
public static final boolean MAP_NO_RECURSE = false;
public static final boolean MAP_RECURSE = true;
- // The screen id used for the empty screen always present to the right.
- public static final int EXTRA_EMPTY_SCREEN_ID = -201;
- // The is the first screen. It is always present, even if its empty.
- public static final int FIRST_SCREEN_ID = 0;
-
private LayoutTransition mLayoutTransition;
@Thunk final WallpaperManager mWallpaperManager;
@@ -740,6 +734,17 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
return newId;
}
+ @Override
+ public Hotseat getHotseat() {
+ return mLauncher.getHotseat();
+ }
+
+ @Override
+ public void onAddDropTarget(DropTarget target) {
+ mDragController.addDropTarget(target);
+ }
+
+ @Override
public CellLayout getScreenWithId(int screenId) {
return mWorkspaceScreens.get(screenId);
}
@@ -836,107 +841,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
}
/**
- * At bind time, we use the rank (screenId) to compute x and y for hotseat items.
- * See {@link #addInScreen}.
- */
- public void addInScreenFromBind(View child, ItemInfo info) {
- int x = info.cellX;
- int y = info.cellY;
- if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- int screenId = (int) info.screenId;
- x = mLauncher.getHotseat().getCellXFromOrder(screenId);
- y = mLauncher.getHotseat().getCellYFromOrder(screenId);
- }
- addInScreen(child, info.container, info.screenId, x, y, info.spanX, info.spanY);
- }
-
- /**
- * Adds the specified child in the specified screen based on the {@param info}
- * See {@link #addInScreen(View, int, int, int, int, int, int)}.
- */
- public void addInScreen(View child, ItemInfo info) {
- addInScreen(child, info.container, info.screenId, info.cellX, info.cellY,
- info.spanX, info.spanY);
- }
-
- /**
- * Adds the specified child in the specified screen. The position and dimension of
- * the child are defined by x, y, spanX and spanY.
- *
- * @param child The child to add in one of the workspace's screens.
- * @param screenId The screen in which to add the child.
- * @param x The X position of the child in the screen's grid.
- * @param y The Y position of the child in the screen's grid.
- * @param spanX The number of cells spanned horizontally by the child.
- * @param spanY The number of cells spanned vertically by the child.
- */
- private void addInScreen(View child, int container, int screenId, int x, int y,
- int spanX, int spanY) {
- if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
- if (getScreenWithId(screenId) == null) {
- Log.e(TAG, "Skipping child, screenId " + screenId + " not found");
- // DEBUGGING - Print out the stack trace to see where we are adding from
- new Throwable().printStackTrace();
- return;
- }
- }
- if (screenId == EXTRA_EMPTY_SCREEN_ID) {
- // This should never happen
- throw new RuntimeException("Screen id should not be EXTRA_EMPTY_SCREEN_ID");
- }
-
- final CellLayout layout;
- if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- layout = mLauncher.getHotseat();
-
- // Hide folder title in the hotseat
- if (child instanceof FolderIcon) {
- ((FolderIcon) child).setTextVisible(false);
- }
- } else {
- // Show folder title if not in the hotseat
- if (child instanceof FolderIcon) {
- ((FolderIcon) child).setTextVisible(true);
- }
- layout = getScreenWithId(screenId);
- }
-
- ViewGroup.LayoutParams genericLp = child.getLayoutParams();
- CellLayout.LayoutParams lp;
- if (genericLp == null || !(genericLp instanceof CellLayout.LayoutParams)) {
- lp = new CellLayout.LayoutParams(x, y, spanX, spanY);
- } else {
- lp = (CellLayout.LayoutParams) genericLp;
- lp.cellX = x;
- lp.cellY = y;
- lp.cellHSpan = spanX;
- lp.cellVSpan = spanY;
- }
-
- if (spanX < 0 && spanY < 0) {
- lp.isLockedToGrid = false;
- }
-
- // Get the canonical child id to uniquely represent this view in this screen
- ItemInfo info = (ItemInfo) child.getTag();
- int childId = mLauncher.getViewIdForItem(info);
-
- boolean markCellsAsOccupied = !(child instanceof Folder);
- if (!layout.addViewToCellLayout(child, -1, childId, lp, markCellsAsOccupied)) {
- // TODO: This branch occurs when the workspace is adding views
- // outside of the defined grid
- // maybe we should be deleting these items from the LauncherModel?
- Log.e(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout");
- }
-
- child.setHapticFeedbackEnabled(false);
- child.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE);
- if (child instanceof DropTarget) {
- mDragController.addDropTarget((DropTarget) child);
- }
- }
-
- /**
* Called directly from a CellLayout (not by the framework), after we've been added as a
* listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout
* that it should intercept touch events, which is not something that is normally supported.
diff --git a/src/com/android/launcher3/WorkspaceLayoutManager.java b/src/com/android/launcher3/WorkspaceLayoutManager.java
new file mode 100644
index 000000000..ea2d4d099
--- /dev/null
+++ b/src/com/android/launcher3/WorkspaceLayoutManager.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2018 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.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.launcher3.folder.Folder;
+import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.touch.ItemLongClickListener;
+
+public interface WorkspaceLayoutManager {
+
+ String TAG = "Launcher.Workspace";
+
+ // The screen id used for the empty screen always present to the right.
+ int EXTRA_EMPTY_SCREEN_ID = -201;
+ // The is the first screen. It is always present, even if its empty.
+ int FIRST_SCREEN_ID = 0;
+
+ /**
+ * At bind time, we use the rank (screenId) to compute x and y for hotseat items.
+ * See {@link #addInScreen}.
+ */
+ default void addInScreenFromBind(View child, ItemInfo info) {
+ int x = info.cellX;
+ int y = info.cellY;
+ if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+ int screenId = info.screenId;
+ x = getHotseat().getCellXFromOrder(screenId);
+ y = getHotseat().getCellYFromOrder(screenId);
+ }
+ addInScreen(child, info.container, info.screenId, x, y, info.spanX, info.spanY);
+ }
+
+ /**
+ * Adds the specified child in the specified screen based on the {@param info}
+ * See {@link #addInScreen(View, int, int, int, int, int, int)}.
+ */
+ default void addInScreen(View child, ItemInfo info) {
+ addInScreen(child, info.container, info.screenId, info.cellX, info.cellY,
+ info.spanX, info.spanY);
+ }
+
+ /**
+ * Adds the specified child in the specified screen. The position and dimension of
+ * the child are defined by x, y, spanX and spanY.
+ *
+ * @param child The child to add in one of the workspace's screens.
+ * @param screenId The screen in which to add the child.
+ * @param x The X position of the child in the screen's grid.
+ * @param y The Y position of the child in the screen's grid.
+ * @param spanX The number of cells spanned horizontally by the child.
+ * @param spanY The number of cells spanned vertically by the child.
+ */
+ default void addInScreen(View child, int container, int screenId, int x, int y,
+ int spanX, int spanY) {
+ if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+ if (getScreenWithId(screenId) == null) {
+ Log.e(TAG, "Skipping child, screenId " + screenId + " not found");
+ // DEBUGGING - Print out the stack trace to see where we are adding from
+ new Throwable().printStackTrace();
+ return;
+ }
+ }
+ if (screenId == EXTRA_EMPTY_SCREEN_ID) {
+ // This should never happen
+ throw new RuntimeException("Screen id should not be EXTRA_EMPTY_SCREEN_ID");
+ }
+
+ final CellLayout layout;
+ if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+ layout = getHotseat();
+
+ // Hide folder title in the hotseat
+ if (child instanceof FolderIcon) {
+ ((FolderIcon) child).setTextVisible(false);
+ }
+ } else {
+ // Show folder title if not in the hotseat
+ if (child instanceof FolderIcon) {
+ ((FolderIcon) child).setTextVisible(true);
+ }
+ layout = getScreenWithId(screenId);
+ }
+
+ ViewGroup.LayoutParams genericLp = child.getLayoutParams();
+ CellLayout.LayoutParams lp;
+ if (genericLp == null || !(genericLp instanceof CellLayout.LayoutParams)) {
+ lp = new CellLayout.LayoutParams(x, y, spanX, spanY);
+ } else {
+ lp = (CellLayout.LayoutParams) genericLp;
+ lp.cellX = x;
+ lp.cellY = y;
+ lp.cellHSpan = spanX;
+ lp.cellVSpan = spanY;
+ }
+
+ if (spanX < 0 && spanY < 0) {
+ lp.isLockedToGrid = false;
+ }
+
+ // Get the canonical child id to uniquely represent this view in this screen
+ ItemInfo info = (ItemInfo) child.getTag();
+ int childId = info.getViewId();
+
+ boolean markCellsAsOccupied = !(child instanceof Folder);
+ if (!layout.addViewToCellLayout(child, -1, childId, lp, markCellsAsOccupied)) {
+ // TODO: This branch occurs when the workspace is adding views
+ // outside of the defined grid
+ // maybe we should be deleting these items from the LauncherModel?
+ Log.e(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout");
+ }
+
+ child.setHapticFeedbackEnabled(false);
+ child.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE);
+ if (child instanceof DropTarget) {
+ onAddDropTarget((DropTarget) child);
+ }
+ }
+
+ Hotseat getHotseat();
+
+ CellLayout getScreenWithId(int screenId);
+
+ default void onAddDropTarget(DropTarget target) { }
+}
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 8439e794f..06eaf38bc 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -225,8 +225,7 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> {
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
lp.cellX = item.cellX;
lp.cellY = item.cellY;
- getPageAt(pageNo).addViewToCellLayout(
- view, -1, mFolder.mLauncher.getViewIdForItem(item), lp, true);
+ getPageAt(pageNo).addViewToCellLayout(view, -1, item.getViewId(), lp, true);
}
@SuppressLint("InflateParams")
@@ -351,8 +350,7 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> {
}
lp.cellX = info.cellX;
lp.cellY = info.cellY;
- currentPage.addViewToCellLayout(
- v, -1, mFolder.mLauncher.getViewIdForItem(info), lp, true);
+ currentPage.addViewToCellLayout(v, -1, info.getViewId(), lp, true);
if (verifier.isItemInPreview(rank) && v instanceof BubbleTextView) {
((BubbleTextView) v).verifyHighRes();
diff --git a/src/com/android/launcher3/graphics/FragmentWithPreview.java b/src/com/android/launcher3/graphics/FragmentWithPreview.java
new file mode 100644
index 000000000..250eca29d
--- /dev/null
+++ b/src/com/android/launcher3/graphics/FragmentWithPreview.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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.graphics;
+
+import android.app.Fragment;
+import android.content.Context;
+import android.os.Bundle;
+
+/**
+ * Extension of fragment, with support for preview mode.
+ */
+public class FragmentWithPreview extends Fragment {
+
+ private Context mPreviewContext;
+
+ public final void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ onInit(savedInstanceState);
+ }
+
+ public void onInit(Bundle savedInstanceState) { }
+
+
+ public Context getContext() {
+ return mPreviewContext != null ? mPreviewContext : getActivity();
+ }
+
+ void enterPreviewMode(Context context) {
+ mPreviewContext = context;
+ }
+
+ public boolean isInPreviewMode() {
+ return mPreviewContext != null;
+ }
+}
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
new file mode 100644
index 000000000..dc6f50fdb
--- /dev/null
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2018 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.graphics;
+
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+import static android.view.View.VISIBLE;
+
+import android.annotation.TargetApi;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Process;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextClock;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Hotseat;
+import com.android.launcher3.InsettableFrameLayout;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.R;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.WorkspaceLayoutManager;
+import com.android.launcher3.allapps.SearchUiManager;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.icons.BaseIconFactory;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.BitmapRenderer;
+import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.BaseDragLayer;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Utility class for generating the preview of Launcher for a given InvariantDeviceProfile.
+ * Steps:
+ * 1) Create a dummy icon info with just white icon
+ * 2) Inflate a strip down layout definition for Launcher
+ * 3) Place appropriate elements like icons and first-page qsb
+ * 4) Measure and draw the view on a canvas
+ */
+@TargetApi(Build.VERSION_CODES.O)
+public class LauncherPreviewRenderer {
+
+ private static final String TAG = "LauncherPreviewRenderer";
+
+ private final Handler mUiHandler;
+ private final Context mContext;
+ private final InvariantDeviceProfile mIdp;
+ private final DeviceProfile mDp;
+ private final Rect mInsets;
+
+ private final ShortcutInfo mShortcutInfo;
+
+ public LauncherPreviewRenderer(Context context, InvariantDeviceProfile idp) {
+ mUiHandler = new Handler(Looper.getMainLooper());
+ mContext = context;
+ mIdp = idp;
+ mDp = idp.portraitProfile.copy(context);
+
+ // TODO: get correct insets once display cutout API is available.
+ mInsets = new Rect();
+ mInsets.left = mInsets.right = (mDp.widthPx - mDp.availableWidthPx) / 2;
+ mInsets.top = mInsets.bottom = (mDp.heightPx - mDp.availableHeightPx) / 2;
+ mDp.updateInsets(mInsets);
+
+ BaseIconFactory iconFactory =
+ new BaseIconFactory(context, mIdp.fillResIconDpi, mIdp.iconBitmapSize) { };
+ BitmapInfo iconInfo = iconFactory.createBadgedIconBitmap(new AdaptiveIconDrawable(
+ new ColorDrawable(Color.WHITE), new ColorDrawable(Color.WHITE)),
+ Process.myUserHandle(),
+ Build.VERSION.SDK_INT);
+
+ mShortcutInfo = new ShortcutInfo();
+ mShortcutInfo.applyFrom(iconInfo);
+ mShortcutInfo.intent = new Intent();
+ mShortcutInfo.contentDescription = mShortcutInfo.title =
+ context.getString(R.string.label_application);
+ }
+
+ public Bitmap createScreenShot() {
+ return BitmapRenderer.createHardwareBitmap(mDp.widthPx, mDp.heightPx, c -> {
+
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ new MainThreadRenderer(mContext).renderScreenShot(c);
+ } else {
+ CountDownLatch latch = new CountDownLatch(1);
+ Utilities.postAsyncCallback(mUiHandler, () -> {
+ new MainThreadRenderer(mContext).renderScreenShot(c);
+ latch.countDown();
+ });
+
+ try {
+ latch.await();
+ } catch (Exception e) {
+ Log.e(TAG, "Error drawing on main thread", e);
+ }
+ }
+ });
+ }
+
+ private class MainThreadRenderer extends ContextThemeWrapper
+ implements ActivityContext, WorkspaceLayoutManager, LayoutInflater.Factory2 {
+
+ private final LayoutInflater mHomeElementInflater;
+ private final InsettableFrameLayout mRootView;
+
+ private final Hotseat mHotseat;
+ private final CellLayout mWorkspace;
+
+ MainThreadRenderer(Context context) {
+ super(context, R.style.AppTheme);
+
+ mHomeElementInflater = LayoutInflater.from(
+ new ContextThemeWrapper(this, R.style.HomeScreenElementTheme));
+ mHomeElementInflater.setFactory2(this);
+
+ mRootView = (InsettableFrameLayout) mHomeElementInflater.inflate(
+ R.layout.launcher_preview_layout, null, false);
+ mRootView.setInsets(mInsets);
+ measureView(mRootView, mDp.widthPx, mDp.heightPx);
+
+ mHotseat = mRootView.findViewById(R.id.hotseat);
+ mHotseat.resetLayout(false);
+
+ mWorkspace = mRootView.findViewById(R.id.workspace);
+ mWorkspace.setPadding(mDp.workspacePadding.left + mDp.cellLayoutPaddingLeftRightPx,
+ mDp.workspacePadding.top,
+ mDp.workspacePadding.right + mDp.cellLayoutPaddingLeftRightPx,
+ mDp.workspacePadding.bottom);
+ }
+
+ @Override
+ public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
+ if ("TextClock".equals(name)) {
+ // Workaround for TextClock accessing handler for unregistering ticker.
+ return new TextClock(context, attrs) {
+
+ @Override
+ public Handler getHandler() {
+ return mUiHandler;
+ }
+ };
+ } else if (!"fragment".equals(name)) {
+ return null;
+ }
+
+ TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PreviewFragment);
+ FragmentWithPreview f = (FragmentWithPreview) Fragment.instantiate(
+ context, ta.getString(R.styleable.PreviewFragment_android_name));
+ f.enterPreviewMode(context);
+ f.onInit(null);
+
+ View view = f.onCreateView(LayoutInflater.from(context), (ViewGroup) parent, null);
+ view.setId(ta.getInt(R.styleable.PreviewFragment_android_id, View.NO_ID));
+ return view;
+ }
+
+ @Override
+ public View onCreateView(String name, Context context, AttributeSet attrs) {
+ return onCreateView(null, name, context, attrs);
+ }
+
+ @Override
+ public BaseDragLayer getDragLayer() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DeviceProfile getDeviceProfile() {
+ return mDp;
+ }
+
+ @Override
+ public Hotseat getHotseat() {
+ return mHotseat;
+ }
+
+ @Override
+ public CellLayout getScreenWithId(int screenId) {
+ return mWorkspace;
+ }
+
+ private void inflateAndAddIcon(ShortcutInfo info) {
+ BubbleTextView icon = (BubbleTextView) mHomeElementInflater.inflate(
+ R.layout.app_icon, mWorkspace, false);
+ icon.applyFromShortcutInfo(info);
+ addInScreenFromBind(icon, info);
+ }
+
+ private void dispatchVisibilityAggregated(View view, boolean isVisible) {
+ // Similar to View.dispatchVisibilityAggregated implementation.
+ final boolean thisVisible = view.getVisibility() == VISIBLE;
+ if (thisVisible || !isVisible) {
+ view.onVisibilityAggregated(isVisible);
+ }
+
+ if (view instanceof ViewGroup) {
+ isVisible = thisVisible && isVisible;
+ ViewGroup vg = (ViewGroup) view;
+ int count = vg.getChildCount();
+
+ for (int i = 0; i < count; i++) {
+ dispatchVisibilityAggregated(vg.getChildAt(i), isVisible);
+ }
+ }
+ }
+
+ private void renderScreenShot(Canvas canvas) {
+ // Add hotseat icons
+ for (int i = 0; i < mIdp.numHotseatIcons; i++) {
+ ShortcutInfo info = new ShortcutInfo(mShortcutInfo);
+ info.container = Favorites.CONTAINER_HOTSEAT;
+ info.screenId = i;
+ inflateAndAddIcon(info);
+ }
+
+ // Add workspace icons
+ for (int i = 0; i < mIdp.numColumns; i++) {
+ ShortcutInfo info = new ShortcutInfo(mShortcutInfo);
+ info.container = Favorites.CONTAINER_DESKTOP;
+ info.screenId = 0;
+ info.cellX = i;
+ info.cellY = mIdp.numRows - 1;
+ inflateAndAddIcon(info);
+ }
+
+ // Add first page QSB
+ if (FeatureFlags.QSB_ON_FIRST_SCREEN.get()) {
+ View qsb = mHomeElementInflater.inflate(
+ R.layout.search_container_workspace, mWorkspace, false);
+ CellLayout.LayoutParams lp =
+ new CellLayout.LayoutParams(0, 0, mWorkspace.getCountX(), 1);
+ lp.canReorder = false;
+ mWorkspace.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true);
+ }
+
+ // Setup search view
+ SearchUiManager searchUiManager =
+ mRootView.findViewById(R.id.search_container_all_apps);
+ mRootView.findViewById(R.id.apps_view).setTranslationY(
+ mDp.heightPx - searchUiManager.getScrollRangeDelta(mInsets));
+
+ measureView(mRootView, mDp.widthPx, mDp.heightPx);
+ dispatchVisibilityAggregated(mRootView, true);
+ measureView(mRootView, mDp.widthPx, mDp.heightPx);
+ // Additional measure for views which use auto text size API
+ measureView(mRootView, mDp.widthPx, mDp.heightPx);
+
+ canvas.drawColor(Color.GRAY);
+ mRootView.draw(canvas);
+ dispatchVisibilityAggregated(mRootView, false);
+ }
+ }
+
+ private static void measureView(View view, int width, int height) {
+ view.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
+ view.layout(0, 0, width, height);
+ }
+}
diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java
index ac1fafb42..57a458b09 100644
--- a/src/com/android/launcher3/qsb/QsbContainerView.java
+++ b/src/com/android/launcher3/qsb/QsbContainerView.java
@@ -44,6 +44,7 @@ import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.graphics.FragmentWithPreview;
/**
* A frame layout which contains a QSB. This internally uses fragment to bind the view, which
@@ -78,7 +79,7 @@ public class QsbContainerView extends FrameLayout {
/**
* A fragment to display the QSB.
*/
- public static class QsbFragment extends Fragment {
+ public static class QsbFragment extends FragmentWithPreview {
public static final int QSB_WIDGET_HOST_ID = 1026;
private static final int REQUEST_BIND_QSB = 1;
@@ -93,14 +94,13 @@ public class QsbContainerView extends FrameLayout {
private int mOrientation;
@Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ public void onInit(Bundle savedInstanceState) {
mQsbWidgetHost = createHost();
mOrientation = getContext().getResources().getConfiguration().orientation;
}
protected QsbWidgetHost createHost() {
- return new QsbWidgetHost(getActivity(), QSB_WIDGET_HOST_ID,
+ return new QsbWidgetHost(getContext(), QSB_WIDGET_HOST_ID,
(c) -> new QsbWidgetHostView(c));
}
@@ -110,7 +110,7 @@ public class QsbContainerView extends FrameLayout {
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- mWrapper = new FrameLayout(getActivity());
+ mWrapper = new FrameLayout(getContext());
// Only add the view when enabled
if (isQsbEnabled()) {
@@ -126,16 +126,16 @@ public class QsbContainerView extends FrameLayout {
return getDefaultView(container, false /* show setup icon */);
}
Bundle opts = createBindOptions();
- Activity activity = getActivity();
- AppWidgetManager widgetManager = AppWidgetManager.getInstance(activity);
+ Context context = getContext();
+ AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
- int widgetId = Utilities.getPrefs(activity).getInt(mKeyWidgetId, -1);
+ int widgetId = Utilities.getPrefs(context).getInt(mKeyWidgetId, -1);
AppWidgetProviderInfo widgetInfo = widgetManager.getAppWidgetInfo(widgetId);
boolean isWidgetBound = (widgetInfo != null) &&
widgetInfo.provider.equals(mWidgetInfo.provider);
int oldWidgetId = widgetId;
- if (!isWidgetBound) {
+ if (!isWidgetBound && !isInPreviewMode()) {
if (widgetId > -1) {
// widgetId is already bound and its not the correct provider. reset host.
mQsbWidgetHost.deleteHost();
@@ -155,14 +155,16 @@ public class QsbContainerView extends FrameLayout {
}
if (isWidgetBound) {
- mQsb = (QsbWidgetHostView) mQsbWidgetHost.createView(activity, widgetId, mWidgetInfo);
+ mQsb = (QsbWidgetHostView) mQsbWidgetHost.createView(context, widgetId, mWidgetInfo);
mQsb.setId(R.id.qsb_widget);
- if (!Utilities.containsAll(AppWidgetManager.getInstance(activity)
- .getAppWidgetOptions(widgetId), opts)) {
- mQsb.updateAppWidgetOptions(opts);
+ if (!isInPreviewMode()) {
+ if (!Utilities.containsAll(AppWidgetManager.getInstance(context)
+ .getAppWidgetOptions(widgetId), opts)) {
+ mQsb.updateAppWidgetOptions(opts);
+ }
+ mQsbWidgetHost.startListening();
}
- mQsbWidgetHost.startListening();
return mQsb;
}
@@ -171,7 +173,7 @@ public class QsbContainerView extends FrameLayout {
}
private void saveWidgetId(int widgetId) {
- Utilities.getPrefs(getActivity()).edit().putInt(mKeyWidgetId, widgetId).apply();
+ Utilities.getPrefs(getContext()).edit().putInt(mKeyWidgetId, widgetId).apply();
}
@Override
@@ -206,7 +208,7 @@ public class QsbContainerView extends FrameLayout {
return;
}
- if (mWrapper != null && getActivity() != null) {
+ if (mWrapper != null && getContext() != null) {
mWrapper.removeAllViews();
mWrapper.addView(createQsb(mWrapper));
}
@@ -217,10 +219,10 @@ public class QsbContainerView extends FrameLayout {
}
protected Bundle createBindOptions() {
- InvariantDeviceProfile idp = LauncherAppState.getIDP(getActivity());
+ InvariantDeviceProfile idp = LauncherAppState.getIDP(getContext());
Bundle opts = new Bundle();
- Rect size = AppWidgetResizeFrame.getWidgetSizeRanges(getActivity(),
+ Rect size = AppWidgetResizeFrame.getWidgetSizeRanges(getContext(),
idp.numColumns, 1, null);
opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, size.left);
opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, size.top);
@@ -252,14 +254,14 @@ public class QsbContainerView extends FrameLayout {
*/
protected AppWidgetProviderInfo getSearchWidgetProvider() {
SearchManager searchManager =
- (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
+ (SearchManager) getContext().getSystemService(Context.SEARCH_SERVICE);
ComponentName searchComponent = searchManager.getGlobalSearchActivity();
if (searchComponent == null) return null;
String providerPkg = searchComponent.getPackageName();
AppWidgetProviderInfo defaultWidgetForSearchPackage = null;
- AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getActivity());
+ AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getContext());
for (AppWidgetProviderInfo info : appWidgetManager.getInstalledProviders()) {
if (info.provider.getPackageName().equals(providerPkg) && info.configure == null) {
if ((info.widgetCategory
diff --git a/src/com/android/launcher3/util/MyActivity.java b/src/com/android/launcher3/util/MyActivity.java
new file mode 100644
index 000000000..379a8da4e
--- /dev/null
+++ b/src/com/android/launcher3/util/MyActivity.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 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.util;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.launcher3.LauncherAppState;
+
+import com.android.launcher3.graphics.LauncherPreviewRenderer;
+
+/**
+ * TODO: Remove this class
+ */
+@TargetApi(Build.VERSION_CODES.O)
+public class MyActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ new AsyncTask<Void, Void, Bitmap>() {
+ @Override
+ protected Bitmap doInBackground(Void... voids) {
+ LauncherPreviewRenderer renderer = new LauncherPreviewRenderer(MyActivity.this,
+ LauncherAppState.getIDP(MyActivity.this));
+
+ Bitmap b = renderer.createScreenShot();
+ return b;
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap bitmap) {
+ ImageView view = new ImageView(MyActivity.this);
+ view.setImageBitmap(bitmap);
+ setContentView(view);
+
+ view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+
+ }
+ }.execute();
+ }
+}