Merge "Initial changes to break out AllApps into its own view." into ub-launcher3-burnaby

This commit is contained in:
Winson Chung
2015-03-11 01:31:30 +00:00
committed by Android (Google) Code Review
28 changed files with 2112 additions and 935 deletions
+21
View File
@@ -0,0 +1,21 @@
<?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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#ffffff" />
<corners android:radius="3dp" />
</shape>
+6
View File
@@ -62,6 +62,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
<include layout="@layout/apps_view"
android:id="@+id/apps_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
</com.android.launcher3.DragLayer>
<ViewStub
+6
View File
@@ -71,6 +71,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
<include layout="@layout/apps_view"
android:id="@+id/apps_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
</com.android.launcher3.DragLayer>
<ViewStub
+34
View File
@@ -0,0 +1,34 @@
<?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.
-->
<com.android.launcher3.AppsContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/apps_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp"
android:background="#22000000"
android:descendantFocusability="afterDescendants">
<include
layout="@layout/apps_list_reveal_view"
android:layout_width="420dp"
android:layout_height="match_parent"
android:layout_gravity="center" />
<include
layout="@layout/apps_list_view"
android:layout_width="420dp"
android:layout_height="match_parent"
android:layout_gravity="center" />
</com.android.launcher3.AppsContainerView>
+6
View File
@@ -71,6 +71,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
<include layout="@layout/apps_view"
android:id="@+id/apps_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
</com.android.launcher3.DragLayer>
<ViewStub
+22
View File
@@ -0,0 +1,22 @@
<?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.
-->
<com.android.launcher3.BubbleTextView
xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/WorkspaceIcon.AppsCustomize"
android:id="@+id/application_icon"
android:focusable="true"
android:background="@drawable/focusable_view_bg" />
+38
View File
@@ -0,0 +1,38 @@
<?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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/apps_view_row_height"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:orientation="horizontal"
android:focusable="true"
android:background="@drawable/focusable_view_bg"
android:descendantFocusability="afterDescendants">
<TextView
android:id="@+id/section"
android:layout_width="48dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingRight="8dp"
android:paddingBottom="12dp"
android:gravity="right"
android:textColor="#1ca195"
android:textSize="16sp"
android:textAllCaps="true"
android:focusable="false" />
</LinearLayout>
+25
View File
@@ -0,0 +1,25 @@
<?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.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/all_apps_transition_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:elevation="15dp"
android:visibility="invisible"
android:background="@drawable/apps_list_bg"
android:focusable="false" />
+28
View File
@@ -0,0 +1,28 @@
<?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.
-->
<com.android.launcher3.BubbleTextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
style="@style/WorkspaceIcon.AppsCustomize"
android:id="@+id/application_icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:background="@drawable/focusable_view_bg"
launcher:iconPaddingOverride="24dp"
launcher:textSizeOverride="16dp"
launcher:layoutHorizontal="true" />
+34
View File
@@ -0,0 +1,34 @@
<?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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/apps_view_row_height"
android:orientation="horizontal"
android:focusable="true"
android:background="@drawable/focusable_view_bg"
android:descendantFocusability="afterDescendants">
<TextView
android:id="@+id/section"
android:layout_width="64dp"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:gravity="left|center_vertical"
android:textColor="#009688"
android:textSize="24sp"
android:textAllCaps="true"
android:focusable="false" />
</LinearLayout>
+30
View File
@@ -0,0 +1,30 @@
<?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.
-->
<ListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/apps_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:clipToPadding="false"
android:scrollbars="vertical"
android:elevation="15dp"
android:background="@drawable/apps_list_bg"
android:visibility="gone"
android:focusable="true"
android:descendantFocusability="afterDescendants" />
+28
View File
@@ -0,0 +1,28 @@
<?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.
-->
<com.android.launcher3.AppsContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/apps_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp"
android:background="#22000000"
android:descendantFocusability="afterDescendants">
<include
layout="@layout/apps_list_reveal_view" />
<include
layout="@layout/apps_list_view" />
</com.android.launcher3.AppsContainerView>
+3
View File
@@ -17,6 +17,9 @@
<resources>
<dimen name="app_icon_size">64dp</dimen>
<!-- Apps view -->
<dimen name="apps_view_row_height">76dp</dimen>
<!-- AppsCustomize -->
<dimen name="apps_customize_tab_bar_height">60dp</dimen>
<dimen name="apps_customize_tab_bar_margin_top">8dp</dimen>
+8
View File
@@ -18,6 +18,14 @@
<resources>
<!-- BubbleTextView specific attributes. -->
<declare-styleable name="BubbleTextView">
<attr name="layoutHorizontal" format="boolean" />
<attr name="iconSizeOverride" format="dimension" />
<attr name="iconPaddingOverride" format="dimension" />
<attr name="textSizeOverride" format="dimension" />
</declare-styleable>
<!-- Page Indicator specific attributes. -->
<declare-styleable name="PageIndicator">
<attr name="windowSize" format="integer" />
+3
View File
@@ -46,6 +46,9 @@
<dimen name="toolbar_button_vertical_padding">4dip</dimen>
<dimen name="toolbar_button_horizontal_padding">12dip</dimen>
<!-- Apps view -->
<dimen name="apps_view_row_height">64dp</dimen>
<!-- AllApps/Customize/AppsCustomize -->
<!-- The height of the tab bar - if this changes, we should update the
external icon width/height above to compensate -->
@@ -0,0 +1,609 @@
package com.android.launcher3;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SectionIndexer;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Represents a row in the apps list view.
*/
class AppsRow {
int sectionId;
String sectionDescription;
List<AppInfo> apps;
public AppsRow(int sId, String sc, List<AppInfo> ai) {
sectionId = sId;
sectionDescription = sc;
apps = ai;
}
public AppsRow(int sId, List<AppInfo> ai) {
sectionId = sId;
apps = ai;
}
}
/**
* An interface to an algorithm that generates app rows.
*/
interface AppRowAlgorithm {
public List<AppsRow> computeAppRows(List<AppInfo> sortedApps, int appsPerRow);
public int getIconViewLayoutId();
public int getRowViewLayoutId();
public void bindRowViewIconToInfo(BubbleTextView icon, AppInfo info);
}
/**
* Computes the rows in the apps list view.
*/
class SectionedAppsAlgorithm implements AppRowAlgorithm {
@Override
public List<AppsRow> computeAppRows(List<AppInfo> sortedApps, int appsPerRow) {
List<AppsRow> rows = new ArrayList<>();
LinkedHashMap<String, List<AppInfo>> sections = computeSectionedApps(sortedApps);
int sectionId = 0;
for (Map.Entry<String, List<AppInfo>> sectionEntry : sections.entrySet()) {
String section = sectionEntry.getKey();
List<AppInfo> apps = sectionEntry.getValue();
int numRows = (int) Math.ceil((float) apps.size() / appsPerRow);
for (int i = 0; i < numRows; i++) {
List<AppInfo> appsInRow = new ArrayList<>();
int offset = i * appsPerRow;
for (int j = 0; j < appsPerRow; j++) {
if (offset + j < apps.size()) {
appsInRow.add(apps.get(offset + j));
}
}
if (i == 0) {
rows.add(new AppsRow(sectionId, section, appsInRow));
} else {
rows.add(new AppsRow(sectionId, appsInRow));
}
}
sectionId++;
}
return rows;
}
@Override
public int getIconViewLayoutId() {
return R.layout.apps_grid_row_icon_view;
}
@Override
public int getRowViewLayoutId() {
return R.layout.apps_grid_row_view;
}
private LinkedHashMap<String, List<AppInfo>> computeSectionedApps(List<AppInfo> sortedApps) {
LinkedHashMap<String, List<AppInfo>> sections = new LinkedHashMap<>();
for (AppInfo info : sortedApps) {
String section = getSection(info);
List<AppInfo> sectionApps = sections.get(section);
if (sectionApps == null) {
sectionApps = new ArrayList<>();
sections.put(section, sectionApps);
}
sectionApps.add(info);
}
return sections;
}
@Override
public void bindRowViewIconToInfo(BubbleTextView icon, AppInfo info) {
icon.applyFromApplicationInfo(info);
}
private String getSection(AppInfo app) {
return app.title.toString().substring(0, 1).toLowerCase();
}
}
/**
* Computes the rows in the apps grid view.
*/
class ListedAppsAlgorithm implements AppRowAlgorithm {
@Override
public List<AppsRow> computeAppRows(List<AppInfo> sortedApps, int appsPerRow) {
List<AppsRow> rows = new ArrayList<>();
int sectionId = -1;
String prevSection = "";
for (AppInfo info : sortedApps) {
List<AppInfo> appsInRow = new ArrayList<>();
appsInRow.add(info);
String section = getSection(info);
if (!prevSection.equals(section)) {
prevSection = section;
sectionId++;
rows.add(new AppsRow(sectionId, section, appsInRow));
} else {
rows.add(new AppsRow(sectionId, appsInRow));
}
}
return rows;
}
@Override
public int getIconViewLayoutId() {
return R.layout.apps_list_row_icon_view;
}
@Override
public int getRowViewLayoutId() {
return R.layout.apps_list_row_view;
}
@Override
public void bindRowViewIconToInfo(BubbleTextView icon, AppInfo info) {
icon.applyFromApplicationInfo(info);
}
private String getSection(AppInfo app) {
return app.title.toString().substring(0, 1).toLowerCase();
}
}
/**
* The adapter of all the apps
*/
class AppsListAdapter extends BaseAdapter implements SectionIndexer {
private LayoutInflater mLayoutInflater;
private List<AppsRow> mAppRows = new ArrayList<>();
private View.OnTouchListener mTouchListener;
private View.OnClickListener mIconClickListener;
private View.OnLongClickListener mIconLongClickListener;
private AppRowAlgorithm mRowAlgorithm;
private int mAppsPerRow;
public AppsListAdapter(Context context, View.OnTouchListener touchListener,
View.OnClickListener iconClickListener, View.OnLongClickListener iconLongClickListener) {
mLayoutInflater = LayoutInflater.from(context);
mTouchListener = touchListener;
mIconClickListener = iconClickListener;
mIconLongClickListener = iconLongClickListener;
}
void setApps(List<AppsRow> apps, int appsPerRow, AppRowAlgorithm algo) {
mAppsPerRow = appsPerRow;
mRowAlgorithm = algo;
mAppRows.clear();
mAppRows.addAll(apps);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mAppRows.size();
}
@Override
public Object getItem(int position) {
return mAppRows.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
AppsRow info = mAppRows.get(position);
ViewGroup row = (ViewGroup) convertView;
if (row == null) {
// Inflate the row and all the icon children necessary
row = (ViewGroup) mLayoutInflater.inflate(mRowAlgorithm.getRowViewLayoutId(),
parent, false);
for (int i = 0; i < mAppsPerRow; i++) {
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
mRowAlgorithm.getIconViewLayoutId(), row, false);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(0,
ViewGroup.LayoutParams.WRAP_CONTENT, 1);
lp.gravity = Gravity.CENTER_VERTICAL;
icon.setLayoutParams(lp);
icon.setOnTouchListener(mTouchListener);
icon.setOnClickListener(mIconClickListener);
icon.setOnLongClickListener(mIconLongClickListener);
icon.setFocusable(true);
row.addView(icon);
}
}
// Bind the section header
TextView tv = (TextView) row.findViewById(R.id.section);
if (info.sectionDescription != null) {
tv.setText(info.sectionDescription);
tv.setVisibility(View.VISIBLE);
} else {
tv.setVisibility(View.INVISIBLE);
}
// Bind the icons
for (int i = 0; i < mAppsPerRow; i++) {
BubbleTextView icon = (BubbleTextView) row.getChildAt(i + 1);
if (i < info.apps.size()) {
mRowAlgorithm.bindRowViewIconToInfo(icon, info.apps.get(i));
icon.setVisibility(View.VISIBLE);
} else {
icon.setVisibility(View.INVISIBLE);
}
}
return row;
}
@Override
public Object[] getSections() {
ArrayList<Object> sections = new ArrayList<>();
int prevSectionId = -1;
for (AppsRow row : mAppRows) {
if (row.sectionId != prevSectionId) {
sections.add(row.sectionDescription.toUpperCase());
prevSectionId = row.sectionId;
}
}
return sections.toArray();
}
@Override
public int getPositionForSection(int sectionIndex) {
for (int i = 0; i < mAppRows.size(); i++) {
AppsRow row = mAppRows.get(i);
if (row.sectionId == sectionIndex) {
return i;
}
}
return 0;
}
@Override
public int getSectionForPosition(int position) {
return mAppRows.get(position).sectionId;
}
}
/**
* The alphabetically sorted list of applications.
*/
class AlphabeticalAppList {
/**
* Callbacks for when this list is modified.
*/
public interface Callbacks {
public void onAppsUpdated();
}
private List<AppInfo> mApps;
private Callbacks mCb;
public AlphabeticalAppList(Callbacks cb) {
mCb = cb;
}
/**
* Returns the list of applications.
*/
public List<AppInfo> getApps() {
return mApps;
}
/**
* Sets the current set of apps.
*/
public void setApps(List<AppInfo> apps) {
Collections.sort(apps, LauncherModel.getAppNameComparator());
mApps = apps;
mCb.onAppsUpdated();
}
/**
* Adds new apps to the list.
*/
public void addApps(List<AppInfo> apps) {
// We add it in place, in alphabetical order
Comparator<AppInfo> appNameComparator = LauncherModel.getAppNameComparator();
for (AppInfo info : apps) {
// This call will return the exact index of where the item is if >= 0, or the index
// where it should be inserted if < 0.
int index = Collections.binarySearch(mApps, info, appNameComparator);
if (index < 0) {
mApps.add(-(index + 1), info);
}
}
mCb.onAppsUpdated();
}
/**
* Updates existing apps in the list
*/
public void updateApps(List<AppInfo> apps) {
Comparator<AppInfo> appNameComparator = LauncherModel.getAppNameComparator();
for (AppInfo info : apps) {
int index = mApps.indexOf(info);
if (index != -1) {
mApps.set(index, info);
} else {
index = Collections.binarySearch(mApps, info, appNameComparator);
if (index < 0) {
mApps.add(-(index + 1), info);
}
}
}
mCb.onAppsUpdated();
}
/**
* Removes some apps from the list.
*/
public void removeApps(List<AppInfo> apps) {
for (AppInfo info : apps) {
int removeIndex = findAppByComponent(mApps, info);
if (removeIndex != -1) {
mApps.remove(removeIndex);
}
}
mCb.onAppsUpdated();
}
/**
* Finds the index of an app given a target AppInfo.
*/
private int findAppByComponent(List<AppInfo> apps, AppInfo targetInfo) {
ComponentName targetComponent = targetInfo.intent.getComponent();
int length = apps.size();
for (int i = 0; i < length; ++i) {
AppInfo info = apps.get(i);
if (info.user.equals(info.user)
&& info.intent.getComponent().equals(targetComponent)) {
return i;
}
}
return -1;
}
}
/**
* The all apps list view container.
*/
public class AppsContainerView extends FrameLayout implements DragSource, View.OnTouchListener,
View.OnLongClickListener, Insettable, AlphabeticalAppList.Callbacks {
static final int GRID_LAYOUT = 0;
static final int LIST_LAYOUT = 1;
static final int USE_LAYOUT = LIST_LAYOUT;
private Launcher mLauncher;
private AppRowAlgorithm mAppRowsAlgorithm;
private AppsListAdapter mAdapter;
private AlphabeticalAppList mApps;
private ListView mList;
private int mAppsRowSize;
private Point mLastTouchDownPos = new Point();
private Rect mPadding = new Rect();
public AppsContainerView(Context context) {
this(context, null);
}
public AppsContainerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public AppsContainerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
mLauncher = (Launcher) context;
if (USE_LAYOUT == GRID_LAYOUT) {
mAppRowsAlgorithm = new SectionedAppsAlgorithm();
mAppsRowSize = grid.allAppsRowsSize;
} else if (USE_LAYOUT == LIST_LAYOUT) {
mAppRowsAlgorithm = new ListedAppsAlgorithm();
mAppsRowSize = 1;
}
mAdapter = new AppsListAdapter(context, this, mLauncher, this);
mApps = new AlphabeticalAppList(this);
}
/**
* Sets the current set of apps.
*/
public void setApps(List<AppInfo> apps) {
mApps.setApps(apps);
}
/**
* Adds new apps to the list.
*/
public void addApps(List<AppInfo> apps) {
mApps.addApps(apps);
}
/**
* Updates existing apps in the list
*/
public void updateApps(List<AppInfo> apps) {
mApps.updateApps(apps);
}
/**
* Removes some apps from the list.
*/
public void removeApps(List<AppInfo> apps) {
mApps.removeApps(apps);
}
/**
* Scrolls this list view to the top.
*/
public void scrollToTop() {
mList.scrollTo(0, 0);
}
/**
* Returns the content view used for the launcher transitions.
*/
public View getContentView() {
return findViewById(R.id.apps_list);
}
/**
* Returns the reveal view used for the launcher transitions.
*/
public View getRevealView() {
return findViewById(R.id.all_apps_transition_overlay);
}
@Override
public void onAppsUpdated() {
List<AppsRow> rows = mAppRowsAlgorithm.computeAppRows(mApps.getApps(), mAppsRowSize);
mAdapter.setApps(rows, mAppsRowSize, mAppRowsAlgorithm);
}
@Override
protected void onFinishInflate() {
mList = (ListView) findViewById(R.id.apps_list);
mList.setFastScrollEnabled(true);
mList.setFastScrollAlwaysVisible(true);
mList.setItemsCanFocus(true);
mList.setAdapter(mAdapter);
mPadding.set(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom());
}
@Override
public void setInsets(Rect insets) {
setPadding(mPadding.left + insets.left, mPadding.top + insets.top,
mPadding.right + insets.right, mPadding.bottom + insets.bottom);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN ||
event.getAction() == MotionEvent.ACTION_MOVE) {
mLastTouchDownPos.set((int) event.getX(), (int) event.getY());
}
return false;
}
@Override
public boolean onLongClick(View v) {
// Return early if this is not initiated from a touch
if (!v.isInTouchMode()) return false;
// When we have exited all apps or are in transition, disregard long clicks
if (!mLauncher.isAppsViewVisible() ||
mLauncher.getWorkspace().isSwitchingState()) return false;
// Return if global dragging is not enabled
if (!mLauncher.isDraggingEnabled()) return false;
// Start the drag
mLauncher.getWorkspace().beginDragShared(v, mLastTouchDownPos, this, false);
// We delay entering spring-loaded mode slightly to make sure the UI
// thready is free of any work.
postDelayed(new Runnable() {
@Override
public void run() {
// We don't enter spring-loaded mode if the drag has been cancelled
if (mLauncher.getDragController().isDragging()) {
// Go into spring loaded mode (must happen before we startDrag())
mLauncher.enterSpringLoadedDragMode();
}
}
}, 150);
return false;
}
@Override
public boolean supportsFlingToDelete() {
return true;
}
@Override
public boolean supportsAppInfoDropTarget() {
return true;
}
@Override
public boolean supportsDeleteDropTarget() {
return true;
}
@Override
public float getIntrinsicIconScaleFactor() {
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
return (float) grid.allAppsIconSizePx / grid.iconSizePx;
}
@Override
public void onFlingToDeleteCompleted() {
// We just dismiss the drag when we fling, so cleanup here
mLauncher.exitSpringLoadedDragModeDelayed(true,
Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
mLauncher.unlockScreenOrientation(false);
}
@Override
public void onDropCompleted(View target, DropTarget.DragObject d, boolean isFlingToDelete, boolean success) {
if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
!(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
// Exit spring loaded mode if we have not successfully dropped or have not handled the
// drop in Workspace
mLauncher.exitSpringLoadedDragModeDelayed(true,
Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
}
mLauncher.unlockScreenOrientation(false);
// Display an error message if the drag failed due to there not being enough space on the
// target layout we were dropping on.
if (!success) {
boolean showOutOfSpaceMessage = false;
if (target instanceof Workspace) {
int currentScreen = mLauncher.getCurrentWorkspaceScreen();
Workspace workspace = (Workspace) target;
CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
ItemInfo itemInfo = (ItemInfo) d.dragInfo;
if (layout != null) {
layout.calculateSpans(itemInfo);
showOutOfSpaceMessage =
!layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
}
}
if (showOutOfSpaceMessage) {
mLauncher.showOutOfSpaceMessage(false);
}
d.deferDragViewCleanupPostAnimation = false;
}
}
}
@@ -149,10 +149,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
* The different content types that this paged view can show.
*/
public enum ContentType {
Applications,
Widgets
}
private ContentType mContentType = ContentType.Applications;
private ContentType mContentType = ContentType.Widgets;
// Refs
private Launcher mLauncher;
@@ -164,7 +163,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
private int mSaveInstanceStateItemIndex = -1;
// Content
private ArrayList<AppInfo> mApps;
private ArrayList<Object> mWidgets;
// Caching
@@ -174,9 +172,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
private int mContentWidth, mContentHeight;
private int mWidgetCountX, mWidgetCountY;
private PagedViewCellLayout mWidgetSpacingLayout;
private int mNumAppsPages;
private int mNumWidgetPages;
private Rect mAllAppsPadding = new Rect();
// Previews & outlines
ArrayList<AppsCustomizeAsyncTask> mRunningTasks;
@@ -214,10 +210,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
super(context, attrs);
mLayoutInflater = LayoutInflater.from(context);
mPackageManager = context.getPackageManager();
mApps = new ArrayList<AppInfo>();
mWidgets = new ArrayList<Object>();
mWidgets = new ArrayList<>();
mIconCache = (LauncherAppState.getInstance()).getIconCache();
mRunningTasks = new ArrayList<AppsCustomizeAsyncTask>();
mRunningTasks = new ArrayList<>();
// Save the default widget preview background
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0);
@@ -256,10 +251,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
grid.edgeMarginPx, 2 * grid.edgeMarginPx);
}
void setAllAppsPadding(Rect r) {
mAllAppsPadding.set(r);
}
void setWidgetsPageIndicatorPadding(int pageIndicatorHeight) {
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), pageIndicatorHeight);
}
@@ -277,22 +268,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
int i = -1;
if (getPageCount() > 0) {
int currentPage = getCurrentPage();
if (mContentType == ContentType.Applications) {
AppsCustomizeCellLayout layout = (AppsCustomizeCellLayout) getPageAt(currentPage);
ShortcutAndWidgetContainer childrenLayout = layout.getShortcutsAndWidgets();
int numItemsPerPage = mCellCountX * mCellCountY;
int childCount = childrenLayout.getChildCount();
if (childCount > 0) {
i = (currentPage * numItemsPerPage) + (childCount / 2);
}
} else if (mContentType == ContentType.Widgets) {
int numApps = mApps.size();
if (mContentType == ContentType.Widgets) {
PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(currentPage);
int numItemsPerPage = mWidgetCountX * mWidgetCountY;
int childCount = layout.getChildCount();
if (childCount > 0) {
i = numApps +
(currentPage * numItemsPerPage) + (childCount / 2);
i = (currentPage * numItemsPerPage) + (childCount / 2);
}
} else {
throw new RuntimeException("Invalid ContentType");
@@ -314,13 +295,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
int getPageForComponent(int index) {
if (index < 0) return 0;
if (index < mApps.size()) {
int numItemsPerPage = mCellCountX * mCellCountY;
return (index / numItemsPerPage);
} else {
int numItemsPerPage = mWidgetCountX * mWidgetCountY;
return (index - mApps.size()) / numItemsPerPage;
}
int numItemsPerPage = mWidgetCountX * mWidgetCountY;
return index / numItemsPerPage;
}
/** Restores the page for an item at the specified index */
@@ -332,16 +308,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
private void updatePageCounts() {
mNumWidgetPages = (int) Math.ceil(mWidgets.size() /
(float) (mWidgetCountX * mWidgetCountY));
mNumAppsPages = (int) Math.ceil((float) mApps.size() / (mCellCountX * mCellCountY));
}
protected void onDataReady(int width, int height) {
// Now that the data is ready, we can calculate the content width, the number of cells to
// use for each page
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
mCellCountX = (int) grid.allAppsNumCols;
mCellCountY = (int) grid.allAppsNumRows;
updatePageCounts();
// Force a measure to update recalculate the gaps
@@ -360,7 +329,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
super.onLayout(changed, l, t, r, b);
if (!isDataReady()) {
if ((!mApps.isEmpty()) && !mWidgets.isEmpty()) {
if (!mWidgets.isEmpty()) {
post(new Runnable() {
// This code triggers requestLayout so must be posted outside of the
// layout pass.
@@ -438,7 +407,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
@Override
public void onClick(View v) {
// When we have exited all apps or are in transition, disregard clicks
if (!mLauncher.isAllAppsVisible()
if (!mLauncher.isWidgetsViewVisible()
|| mLauncher.getWorkspace().isSwitchingState()
|| !(v instanceof PagedViewWidget)) return;
@@ -456,11 +425,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
*/
@Override
protected void determineDraggingStart(android.view.MotionEvent ev) {
// Disable dragging by pulling an app down for now.
}
private void beginDraggingApplication(View v) {
mLauncher.getWorkspace().beginDragShared(v, this);
}
static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
@@ -681,12 +645,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
protected boolean beginDragging(final View v) {
if (!super.beginDragging(v)) return false;
if (v instanceof BubbleTextView) {
beginDraggingApplication(v);
} else if (v instanceof PagedViewWidget) {
if (v instanceof PagedViewWidget) {
if (!beginDraggingWidget(v)) {
return false;
}
} else {
Log.e(TAG, "Unexpected dragging view: " + v);
}
// We delay entering spring-loaded mode slightly to make sure the UI
@@ -852,7 +816,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
// Clean up all the async tasks
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
while (iter.hasNext()) {
AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
AppsCustomizeAsyncTask task = iter.next();
task.cancel(false);
iter.remove();
mDirtyPageContent.set(task.page, true);
@@ -886,7 +850,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
// Update the thread priorities given the direction lookahead
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
while (iter.hasNext()) {
AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
AppsCustomizeAsyncTask task = iter.next();
int pageIndex = task.page;
if ((mNextPage > mCurrentPage && pageIndex >= mCurrentPage) ||
(mNextPage < mCurrentPage && pageIndex <= mCurrentPage)) {
@@ -897,36 +861,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
}
}
/*
* Apps PagedView implementation
*/
private void setVisibilityOnChildren(ViewGroup layout, int visibility) {
int childCount = layout.getChildCount();
for (int i = 0; i < childCount; ++i) {
layout.getChildAt(i).setVisibility(visibility);
}
}
private void setupPage(AppsCustomizeCellLayout layout) {
layout.setGridSize(mCellCountX, mCellCountY);
// Note: We force a measure here to get around the fact that when we do layout calculations
// immediately after syncing, we don't have a proper width. That said, we already know the
// expected page width, so we can actually optimize by hiding all the TextView-based
// children that are expensive to measure, and let that happen naturally later.
setVisibilityOnChildren(layout, View.GONE);
int widthSpec = MeasureSpec.makeMeasureSpec(mContentWidth, MeasureSpec.AT_MOST);
int heightSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.AT_MOST);
layout.measure(widthSpec, heightSpec);
Drawable bg = getContext().getResources().getDrawable(R.drawable.quantum_panel);
if (bg != null) {
bg.setAlpha(mPageBackgroundsVisible ? 255: 0);
layout.setBackground(bg);
}
setVisibilityOnChildren(layout, View.VISIBLE);
}
public void setPageBackgroundsVisible(boolean visible) {
mPageBackgroundsVisible = visible;
int childCount = getChildCount();
@@ -938,43 +872,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
}
}
public void syncAppsPageItems(int page, boolean immediate) {
// ensure that we have the right number of items on the pages
final boolean isRtl = isLayoutRtl();
int numCells = mCellCountX * mCellCountY;
int startIndex = page * numCells;
int endIndex = Math.min(startIndex + numCells, mApps.size());
AppsCustomizeCellLayout layout = (AppsCustomizeCellLayout) getPageAt(page);
layout.removeAllViewsOnPage();
ArrayList<Object> items = new ArrayList<Object>();
ArrayList<Bitmap> images = new ArrayList<Bitmap>();
for (int i = startIndex; i < endIndex; ++i) {
AppInfo info = mApps.get(i);
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
R.layout.apps_customize_application, layout, false);
icon.applyFromApplicationInfo(info);
icon.setOnClickListener(mLauncher);
icon.setOnLongClickListener(this);
icon.setOnTouchListener(this);
icon.setOnKeyListener(mKeyListener);
icon.setOnFocusChangeListener(layout.mFocusHandlerView);
int index = i - startIndex;
int x = index % mCellCountX;
int y = index / mCellCountX;
if (isRtl) {
x = mCellCountX - x - 1;
}
layout.addViewToCellLayout(icon, -1, i, new CellLayout.LayoutParams(x,y, 1,1), false);
items.add(info);
images.add(info.iconBitmap);
}
enableHwLayersOnVisiblePages();
}
/**
* A helper to return the priority for loading of the specified widget page.
*/
@@ -991,7 +888,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
int minPageDiff = Integer.MAX_VALUE;
while (iter.hasNext()) {
AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
AppsCustomizeAsyncTask task = iter.next();
minPageDiff = Math.abs(task.page - toPage);
}
@@ -1026,7 +923,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
// Prune all tasks that are no longer needed
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
while (iter.hasNext()) {
AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
AppsCustomizeAsyncTask task = iter.next();
int taskPage = task.page;
if (taskPage < getAssociatedLowerPageBound(mCurrentPage) ||
taskPage > getAssociatedUpperPageBound(mCurrentPage)) {
@@ -1264,14 +1161,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
cancelAllTasks();
Context context = getContext();
if (mContentType == ContentType.Applications) {
for (int i = 0; i < mNumAppsPages; ++i) {
AppsCustomizeCellLayout layout = new AppsCustomizeCellLayout(context);
setupPage(layout);
addView(layout, new PagedView.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
}
} else if (mContentType == ContentType.Widgets) {
if (mContentType == ContentType.Widgets) {
for (int j = 0; j < mNumWidgetPages; ++j) {
PagedViewGridLayout layout = new PagedViewGridLayout(context, mWidgetCountX,
mWidgetCountY);
@@ -1291,7 +1181,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
if (mContentType == ContentType.Widgets) {
syncWidgetPageItems(page, immediate);
} else {
syncAppsPageItems(page, immediate);
Log.e(TAG, "Unexpected ContentType");
}
}
@@ -1383,7 +1273,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
}
/**
* We should call thise method whenever the core data changes (mApps, mWidgets) so that we can
* We should call thise method whenever the core data changes (mWidgets) so that we can
* appropriately determine when to invalidate the PagedView page data. In cases where the data
* has yet to be set, we can requestLayout() and wait for onDataReady() to be called in the
* next onMeasure() pass, which will trigger an invalidatePageData() itself.
@@ -1399,73 +1289,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
}
}
public void setApps(ArrayList<AppInfo> list) {
mApps = list;
Collections.sort(mApps, LauncherModel.getAppNameComparator());
updatePageCountsAndInvalidateData();
}
public ArrayList<AppInfo> getApps() {
return mApps;
}
private void addAppsWithoutInvalidate(ArrayList<AppInfo> list) {
// We add it in place, in alphabetical order
int count = list.size();
for (int i = 0; i < count; ++i) {
AppInfo info = list.get(i);
int index = Collections.binarySearch(mApps, info, LauncherModel.getAppNameComparator());
if (index < 0) {
mApps.add(-(index + 1), info);
}
}
}
public void addApps(ArrayList<AppInfo> list) {
addAppsWithoutInvalidate(list);
updatePageCountsAndInvalidateData();
}
private int findAppByComponent(List<AppInfo> list, AppInfo item) {
ComponentName removeComponent = item.intent.getComponent();
int length = list.size();
for (int i = 0; i < length; ++i) {
AppInfo info = list.get(i);
if (info.user.equals(item.user)
&& info.intent.getComponent().equals(removeComponent)) {
return i;
}
}
return -1;
}
private void removeAppsWithoutInvalidate(ArrayList<AppInfo> list) {
// loop through all the apps and remove apps that have the same component
int length = list.size();
for (int i = 0; i < length; ++i) {
AppInfo info = list.get(i);
int removeIndex = findAppByComponent(mApps, info);
if (removeIndex > -1) {
mApps.remove(removeIndex);
}
}
}
public void removeApps(ArrayList<AppInfo> appInfos) {
removeAppsWithoutInvalidate(appInfos);
updatePageCountsAndInvalidateData();
}
public void updateApps(ArrayList<AppInfo> list) {
// We remove and re-add the updated applications list because it's properties may have
// changed (ie. the title), and this will ensure that the items will be in their proper
// place in the list.
removeAppsWithoutInvalidate(list);
addAppsWithoutInvalidate(list);
updatePageCountsAndInvalidateData();
}
public void reset() {
// If we have reset, then we should not continue to restore the previous state
mSaveInstanceStateItemIndex = -1;
if (mContentType != ContentType.Applications) {
setContentType(ContentType.Applications);
if (mContentType != ContentType.Widgets) {
setContentType(ContentType.Widgets);
}
if (mCurrentPage != 0) {
@@ -1479,7 +1308,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
public void dumpState() {
// TODO: Dump information related to current list of Applications, Widgets, etc.
AppInfo.dumpApplicationInfoList(TAG, "mApps", mApps);
dumpAppWidgetProviderInfoList(TAG, "mWidgets", mWidgets);
}
@@ -1534,10 +1362,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
int stringId = R.string.default_scroll_format;
int count = 0;
if (mContentType == ContentType.Applications) {
stringId = R.string.apps_customize_apps_scroll_format;
count = mNumAppsPages;
} else if (mContentType == ContentType.Widgets) {
if (mContentType == ContentType.Widgets) {
stringId = R.string.apps_customize_widgets_scroll_format;
count = mNumWidgetPages;
} else {
@@ -27,7 +27,6 @@ import android.widget.FrameLayout;
public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransitionable, Insettable {
static final String LOG_TAG = "AppsCustomizeTabHost";
private static final String APPS_TAB_TAG = "APPS";
private static final String WIDGETS_TAB_TAG = "WIDGETS";
private AppsCustomizePagedView mPagedView;
@@ -50,10 +49,6 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
mPagedView.setContentType(type);
}
public void setCurrentTabFromContent(AppsCustomizePagedView.ContentType type) {
setContentTypeImmediate(type);
}
@Override
public void setInsets(Rect insets) {
mInsets.set(insets);
@@ -78,28 +73,39 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
return getTabTagForContentType(mPagedView.getContentType());
}
/**
* Returns the content view used for the launcher transitions.
*/
public View getContentView() {
return findViewById(R.id.apps_customize_pane_content);
}
/**
* Returns the reveal view used for the launcher transitions.
*/
public View getRevealView() {
return findViewById(R.id.fake_page);
}
/**
* Returns the page indicators view.
*/
public View getPageIndicators() {
return findViewById(R.id.apps_customize_page_indicator);
}
/**
* Returns the content type for the specified tab tag.
*/
public AppsCustomizePagedView.ContentType getContentTypeForTabTag(String tag) {
if (tag.equals(APPS_TAB_TAG)) {
return AppsCustomizePagedView.ContentType.Applications;
} else if (tag.equals(WIDGETS_TAB_TAG)) {
return AppsCustomizePagedView.ContentType.Widgets;
}
return AppsCustomizePagedView.ContentType.Applications;
return AppsCustomizePagedView.ContentType.Widgets;
}
/**
* Returns the tab tag for a given content type.
*/
public String getTabTagForContentType(AppsCustomizePagedView.ContentType type) {
if (type == AppsCustomizePagedView.ContentType.Applications) {
return APPS_TAB_TAG;
} else if (type == AppsCustomizePagedView.ContentType.Widgets) {
return WIDGETS_TAB_TAG;
}
return APPS_TAB_TAG;
return WIDGETS_TAB_TAG;
}
/**
@@ -199,6 +205,7 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
ViewGroup parent = (ViewGroup) getParent();
if (parent == null) return;
View appsView = ((Launcher) getContext()).getAppsView();
View overviewPanel = ((Launcher) getContext()).getOverviewPanel();
final int count = parent.getChildCount();
if (!isChildrenDrawingOrderEnabled()) {
@@ -207,7 +214,8 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
if (child == this) {
break;
} else {
if (child.getVisibility() == GONE || child == overviewPanel) {
if (child.getVisibility() == GONE || child == overviewPanel ||
child == appsView) {
continue;
}
child.setVisibility(visibility);
+63 -38
View File
@@ -28,6 +28,7 @@ import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -49,7 +50,7 @@ public class BubbleTextView extends TextView {
private static final int SHADOW_SMALL_COLOUR = 0xCC000000;
static final float PADDING_V = 3.0f;
private Drawable mIcon;
private final Drawable mBackground;
private final CheckLongPressHelper mLongPressHelper;
private final HolographicOutlineHelper mOutlineHelper;
@@ -62,9 +63,12 @@ public class BubbleTextView extends TextView {
private float mSlop;
private int mTextColor;
private final boolean mCustomShadowsEnabled;
private boolean mIsTextVisible;
private final boolean mLayoutHorizontal;
private final int mIconSize;
private final int mIconPaddingSize;
private final int mTextSize;
private int mTextColor;
private boolean mStayPressed;
private boolean mIgnorePressedStateChange;
@@ -79,10 +83,19 @@ public class BubbleTextView extends TextView {
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.BubbleTextView, defStyle, 0);
mCustomShadowsEnabled = a.getBoolean(R.styleable.BubbleTextView_customShadows, true);
mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
mIconSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconSizeOverride,
grid.allAppsIconSizePx);
mIconPaddingSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconPaddingOverride,
grid.iconDrawablePaddingPx);
mTextSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_textSizeOverride,
grid.allAppsIconTextSizePx);
a.recycle();
if (mCustomShadowsEnabled) {
@@ -92,6 +105,12 @@ public class BubbleTextView extends TextView {
} else {
mBackground = null;
}
// If we are laying out horizontal, then center the text vertically
if (mLayoutHorizontal) {
setGravity(Gravity.CENTER_VERTICAL);
}
mLongPressHelper = new CheckLongPressHelper(this);
mOutlineHelper = HolographicOutlineHelper.obtain(getContext());
@@ -106,9 +125,7 @@ public class BubbleTextView extends TextView {
super.onFinishInflate();
// Ensure we are using the right text size
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
}
public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
@@ -119,16 +136,11 @@ public class BubbleTextView extends TextView {
public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
boolean setDefaultPadding, boolean promiseStateChanged) {
Bitmap b = info.getIcon(iconCache);
LauncherAppState app = LauncherAppState.getInstance();
FastBitmapDrawable iconDrawable = Utilities.createIconDrawable(b);
iconDrawable.setGhostModeEnabled(info.isDisabled != 0);
setCompoundDrawables(null, iconDrawable, null, null);
if (setDefaultPadding) {
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
}
setIcon(iconDrawable, mIconSize, setDefaultPadding ? mIconPaddingSize : -1);
if (info.contentDescription != null) {
setContentDescription(info.contentDescription);
}
@@ -141,13 +153,7 @@ public class BubbleTextView extends TextView {
}
public void applyFromApplicationInfo(AppInfo info) {
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
Drawable topDrawable = Utilities.createIconDrawable(info.iconBitmap);
topDrawable.setBounds(0, 0, grid.allAppsIconSizePx, grid.allAppsIconSizePx);
setCompoundDrawables(null, topDrawable, null, null);
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
setIcon(Utilities.createIconDrawable(info.iconBitmap), mIconSize, mIconPaddingSize);
setText(info.title);
if (info.contentDescription != null) {
setContentDescription(info.contentDescription);
@@ -155,7 +161,6 @@ public class BubbleTextView extends TextView {
setTag(info);
}
@Override
protected boolean setFrame(int left, int top, int right, int bottom) {
if (getLeft() != left || getRight() != right || getTop() != top || getBottom() != bottom) {
@@ -186,10 +191,19 @@ public class BubbleTextView extends TextView {
}
}
/** Returns the icon for this view. */
public Drawable getIcon() {
return mIcon;
}
/** Returns whether the layout is horizontal. */
public boolean isLayoutHorizontal() {
return mLayoutHorizontal;
}
private void updateIconState() {
Drawable top = getCompoundDrawables()[1];
if (top instanceof FastBitmapDrawable) {
((FastBitmapDrawable) top).setPressed(isPressed() || mStayPressed);
if (mIcon instanceof FastBitmapDrawable) {
((FastBitmapDrawable) mIcon).setPressed(isPressed() || mStayPressed);
}
}
@@ -325,10 +339,9 @@ public class BubbleTextView extends TextView {
super.onAttachedToWindow();
if (mBackground != null) mBackground.setCallback(this);
Drawable top = getCompoundDrawables()[1];
if (top instanceof PreloadIconDrawable) {
((PreloadIconDrawable) top).applyPreloaderTheme(getPreloaderTheme());
if (mIcon instanceof PreloadIconDrawable) {
((PreloadIconDrawable) mIcon).applyPreloaderTheme(getPreloaderTheme());
}
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
@@ -358,11 +371,6 @@ public class BubbleTextView extends TextView {
} else {
super.setTextColor(res.getColor(android.R.color.transparent));
}
mIsTextVisible = visible;
}
public boolean isTextVisible() {
return mIsTextVisible;
}
@Override
@@ -385,15 +393,13 @@ public class BubbleTextView extends TextView {
((info.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE) ?
info.getInstallProgress() : 0)) : 100;
Drawable[] drawables = getCompoundDrawables();
Drawable top = drawables[1];
if (top != null) {
if (mIcon != null) {
final PreloadIconDrawable preloadDrawable;
if (top instanceof PreloadIconDrawable) {
preloadDrawable = (PreloadIconDrawable) top;
if (mIcon instanceof PreloadIconDrawable) {
preloadDrawable = (PreloadIconDrawable) mIcon;
} else {
preloadDrawable = new PreloadIconDrawable(top, getPreloaderTheme());
setCompoundDrawables(drawables[0], preloadDrawable, drawables[2], drawables[3]);
preloadDrawable = new PreloadIconDrawable(mIcon, getPreloaderTheme());
setIcon(preloadDrawable, mIconSize, -1);
}
preloadDrawable.setLevel(progressLevel);
@@ -417,4 +423,23 @@ public class BubbleTextView extends TextView {
}
return theme;
}
/**
* Sets the icon for this view based on the layout direction.
*/
private Drawable setIcon(Drawable icon, int iconSize, int drawablePadding) {
mIcon = icon;
if (iconSize != -1) {
mIcon.setBounds(0, 0, iconSize, iconSize);
}
if (mLayoutHorizontal) {
setCompoundDrawablesRelative(mIcon, null, null, null);
} else {
setCompoundDrawablesRelative(null, mIcon, null, null);
}
if (drawablePadding != -1) {
setCompoundDrawablePadding(drawablePadding);
}
return icon;
}
}
@@ -122,6 +122,8 @@ public class DeviceProfile {
int hotseatAllAppsRank;
int allAppsNumRows;
int allAppsNumCols;
// TODO(winsonc): to be used with the grid layout
int allAppsRowsSize;
int searchBarSpaceWidthPx;
int searchBarSpaceHeightPx;
int pageIndicatorHeightPx;
+2 -2
View File
@@ -24,6 +24,7 @@ import android.animation.PropertyValuesHolder;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Build;
@@ -47,7 +48,6 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.launcher3.FolderInfo.FolderListener;
import com.android.launcher3.Workspace.ItemOperator;
@@ -220,7 +220,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
return false;
}
mLauncher.getWorkspace().beginDragShared(v, this);
mLauncher.getWorkspace().beginDragShared(v, new Point(), this, false);
mCurrentDragInfo = item;
mEmptyCellRank = item.rank;
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -3308,7 +3308,7 @@ public class LauncherModel extends BroadcastReceiver
}
}
// Returns a list of ResolveInfos/AppWindowInfos in sorted order
// Returns a list of ResolveInfos/AppWidgetInfos in sorted order
public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {
PackageManager packageManager = context.getPackageManager();
final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();
@@ -0,0 +1,832 @@
/*
* 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.
*/
package com.android.launcher3;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.content.res.Resources;
import android.util.Log;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import java.util.HashMap;
/**
* TODO: figure out what kind of tests we can write for this
*
* Things to test when changing the following class.
* - Home from workspace
* - from center screen
* - from other screens
* - Home from all apps
* - from center screen
* - from other screens
* - Back from all apps
* - from center screen
* - from other screens
* - Launch app from workspace and quit
* - with back
* - with home
* - Launch app from all apps and quit
* - with back
* - with home
* - Go to a screen that's not the default, then all
* apps, and launch and app, and go back
* - with back
* -with home
* - On workspace, long press power and go back
* - with back
* - with home
* - On all apps, long press power and go back
* - with back
* - with home
* - On workspace, power off
* - On all apps, power off
* - Launch an app and turn off the screen while in that app
* - Go back with home key
* - Go back with back key TODO: make this not go to workspace
* - From all apps
* - From workspace
* - Enter and exit car mode (becuase it causes an extra configuration changed)
* - From all apps
* - From the center workspace
* - From another workspace
*/
public class LauncherStateTransitionAnimation {
/**
* Callbacks made during the state transition
*/
interface Callbacks {
public void onStateTransitionHideSearchBar();
}
/**
* Private callbacks made during transition setup.
*/
static abstract class PrivateTransitionCallbacks {
void onRevealViewVisible(View revealView, View contentView, View allAppsButtonView) {}
void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) {}
float getMaterialRevealViewFinalAlpha(View revealView) {
return 0;
}
float getMaterialRevealViewFinalXDrift(View revealView) {
return 0;
}
float getMaterialRevealViewFinalYDrift(View revealView) {
return 0;
}
float getMaterialRevealViewStartFinalRadius() {
return 0;
}
AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(View revealView,
View allAppsButtonView) {
return null;
}
}
public static final String TAG = "LauncherStateTransitionAnimation";
// Flags to determine how to set the layers on views before the transition animation
public static final int BUILD_LAYER = 0;
public static final int BUILD_AND_SET_LAYER = 1;
public static final int SINGLE_FRAME_DELAY = 16;
private Launcher mLauncher;
private Callbacks mCb;
private AnimatorSet mStateAnimation;
public LauncherStateTransitionAnimation(Launcher l, Callbacks cb) {
mLauncher = l;
mCb = cb;
}
/**
* Starts an animation to the apps view.
*/
public void startAnimationToAllApps(final boolean animated) {
final AppsContainerView toView = mLauncher.getAppsView();
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
private int[] mAllAppsToPanelDelta;
@Override
public void onRevealViewVisible(View revealView, View contentView,
View allAppsButtonView) {
toView.setBackground(null);
// Get the y delta between the center of the page and the center of the all apps
// button
mAllAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
allAppsButtonView, null);
}
@Override
public float getMaterialRevealViewFinalAlpha(View revealView) {
return 1f;
}
@Override
public float getMaterialRevealViewFinalXDrift(View revealView) {
return mAllAppsToPanelDelta[0];
}
@Override
public float getMaterialRevealViewFinalYDrift(View revealView) {
return mAllAppsToPanelDelta[1];
}
@Override
public float getMaterialRevealViewStartFinalRadius() {
int allAppsButtonSize = LauncherAppState.getInstance().
getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize;
return allAppsButtonSize / 2;
}
@Override
public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
final View revealView, final View allAppsButtonView) {
return new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animation) {
allAppsButtonView.setVisibility(View.INVISIBLE);
}
public void onAnimationEnd(Animator animation) {
allAppsButtonView.setVisibility(View.VISIBLE);
}
};
}
};
startAnimationToOverlay(Workspace.State.NORMAL_HIDDEN, toView, toView.getContentView(),
toView.getRevealView(), null, animated, cb);
}
/**
* Starts an animation to the widgets view.
*/
public void startAnimationToWidgets(final boolean animated) {
final AppsCustomizeTabHost toView = mLauncher.getWidgetsView();
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
@Override
public void onRevealViewVisible(View revealView, View contentView,
View allAppsButtonView) {
// Hide the real page background, and swap in the fake one
((AppsCustomizePagedView) contentView).setPageBackgroundsVisible(false);
revealView.setBackground(mLauncher.getDrawable(R.drawable.quantum_panel_dark));
}
@Override
public void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) {
// Show the real page background
((AppsCustomizePagedView) contentView).setPageBackgroundsVisible(true);
}
@Override
public float getMaterialRevealViewFinalAlpha(View revealView) {
return 0.3f;
}
@Override
public float getMaterialRevealViewFinalYDrift(View revealView) {
return revealView.getMeasuredHeight() / 2;
}
};
startAnimationToOverlay(Workspace.State.OVERVIEW_HIDDEN, toView, toView.getContentView(),
toView.getRevealView(), toView.getPageIndicators(), animated, cb);
}
/**
* Starts and animation to the workspace from the current overlay view.
*/
public void startAnimationToWorkspace(final Launcher.State fromState,
final Workspace.State toWorkspaceState, final boolean animated,
final Runnable onCompleteRunnable) {
if (toWorkspaceState != Workspace.State.NORMAL &&
toWorkspaceState != Workspace.State.SPRING_LOADED &&
toWorkspaceState != Workspace.State.OVERVIEW) {
Log.e(TAG, "Unexpected call to startAnimationToWorkspace");
}
if (fromState == Launcher.State.APPS || fromState == Launcher.State.APPS_SPRING_LOADED) {
startAnimationToWorkspaceFromAllApps(fromState, toWorkspaceState, animated,
onCompleteRunnable);
} else {
startAnimationToWorkspaceFromWidgets(fromState, toWorkspaceState, animated,
onCompleteRunnable);
}
}
/**
* Creates and starts a new animation to a particular overlay view.
*/
private void startAnimationToOverlay(final Workspace.State toWorkspaceState, final View toView,
final View contentView, final View revealView, final View pageIndicatorsView,
final boolean animated, final PrivateTransitionCallbacks pCb) {
final Resources res = mLauncher.getResources();
final boolean material = Utilities.isLmpOrAbove();
final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
final int itemsAlphaStagger =
res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger);
final View allAppsButtonView = mLauncher.getAllAppsButton();
final View fromView = mLauncher.getWorkspace();
final HashMap<View, Integer> layerViews = new HashMap<>();
// If for some reason our views aren't initialized, don't animate
boolean initialized = allAppsButtonView != null;
// Cancel the current animation
cancelAnimation();
// Create the workspace animation.
// NOTE: this call apparently also sets the state for the workspace if !animated
Animator workspaceAnim = mLauncher.getWorkspace().getChangeStateAnimation(
toWorkspaceState, animated, layerViews);
if (animated && initialized) {
mStateAnimation = LauncherAnimUtils.createAnimatorSet();
// Setup the reveal view animation
int width = revealView.getMeasuredWidth();
int height = revealView.getMeasuredHeight();
float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
revealView.setVisibility(View.VISIBLE);
revealView.setAlpha(0f);
revealView.setTranslationY(0f);
revealView.setTranslationX(0f);
pCb.onRevealViewVisible(revealView, contentView, allAppsButtonView);
// Calculate the final animation values
final float revealViewToAlpha;
final float revealViewToXDrift;
final float revealViewToYDrift;
if (material) {
revealViewToAlpha = pCb.getMaterialRevealViewFinalAlpha(revealView);
revealViewToYDrift = pCb.getMaterialRevealViewFinalYDrift(revealView);
revealViewToXDrift = pCb.getMaterialRevealViewFinalXDrift(revealView);
} else {
revealViewToAlpha = 0f;
revealViewToYDrift = 2 * height / 3;
revealViewToXDrift = 0;
}
// Create the animators
PropertyValuesHolder panelAlpha =
PropertyValuesHolder.ofFloat("alpha", revealViewToAlpha, 1f);
PropertyValuesHolder panelDriftY =
PropertyValuesHolder.ofFloat("translationY", revealViewToYDrift, 0);
PropertyValuesHolder panelDriftX =
PropertyValuesHolder.ofFloat("translationX", revealViewToXDrift, 0);
ObjectAnimator panelAlphaAndDrift = ObjectAnimator.ofPropertyValuesHolder(revealView,
panelAlpha, panelDriftY, panelDriftX);
panelAlphaAndDrift.setDuration(revealDuration);
panelAlphaAndDrift.setInterpolator(new LogDecelerateInterpolator(100, 0));
// Play the animation
layerViews.put(revealView, BUILD_AND_SET_LAYER);
mStateAnimation.play(panelAlphaAndDrift);
// Setup the animation for the page indicators
if (pageIndicatorsView != null) {
pageIndicatorsView.setAlpha(0.01f);
ObjectAnimator indicatorsAlpha =
ObjectAnimator.ofFloat(pageIndicatorsView, "alpha", 1f);
indicatorsAlpha.setDuration(revealDuration);
mStateAnimation.play(indicatorsAlpha);
}
// Setup the animation for the content view
contentView.setVisibility(View.VISIBLE);
contentView.setAlpha(0f);
contentView.setTranslationY(revealViewToYDrift);
layerViews.put(contentView, BUILD_AND_SET_LAYER);
// Create the individual animators
ObjectAnimator pageDrift = ObjectAnimator.ofFloat(contentView, "translationY",
revealViewToYDrift, 0);
pageDrift.setDuration(revealDuration);
pageDrift.setInterpolator(new LogDecelerateInterpolator(100, 0));
pageDrift.setStartDelay(itemsAlphaStagger);
mStateAnimation.play(pageDrift);
ObjectAnimator itemsAlpha = ObjectAnimator.ofFloat(contentView, "alpha", 0f, 1f);
itemsAlpha.setDuration(revealDuration);
itemsAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
itemsAlpha.setStartDelay(itemsAlphaStagger);
mStateAnimation.play(itemsAlpha);
if (material) {
// Animate the all apps button
float startRadius = pCb.getMaterialRevealViewStartFinalRadius();
AnimatorListenerAdapter listener = pCb.getMaterialRevealViewAnimatorListener(
revealView, allAppsButtonView);
Animator reveal = ViewAnimationUtils.createCircularReveal(revealView, width / 2,
height / 2, startRadius, revealRadius);
reveal.setDuration(revealDuration);
reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
if (listener != null) {
reveal.addListener(listener);
}
mStateAnimation.play(reveal);
}
mStateAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
dispatchOnLauncherTransitionEnd(fromView, animated, false);
dispatchOnLauncherTransitionEnd(toView, animated, false);
// Hide the reveal view
revealView.setVisibility(View.INVISIBLE);
pCb.onAnimationComplete(revealView, contentView, allAppsButtonView);
// Disable all necessary layers
for (View v : layerViews.keySet()) {
if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
v.setLayerType(View.LAYER_TYPE_NONE, null);
}
}
// Hide the search bar
mCb.onStateTransitionHideSearchBar();
// This can hold unnecessary references to views.
mStateAnimation = null;
}
});
// Play the workspace animation
if (workspaceAnim != null) {
mStateAnimation.play(workspaceAnim);
}
// Dispatch the prepare transition signal
dispatchOnLauncherTransitionPrepare(fromView, animated, false);
dispatchOnLauncherTransitionPrepare(toView, animated, false);
final AnimatorSet stateAnimation = mStateAnimation;
final Runnable startAnimRunnable = new Runnable() {
public void run() {
// Check that mStateAnimation hasn't changed while
// we waited for a layout/draw pass
if (mStateAnimation != stateAnimation)
return;
dispatchOnLauncherTransitionStart(fromView, animated, false);
dispatchOnLauncherTransitionStart(toView, animated, false);
// Enable all necessary layers
for (View v : layerViews.keySet()) {
if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
if (Utilities.isViewAttachedToWindow(v)) {
v.buildLayer();
}
}
// Focus the new view
toView.requestFocus();
mStateAnimation.start();
}
};
toView.bringToFront();
toView.setVisibility(View.VISIBLE);
toView.post(startAnimRunnable);
} else {
toView.setTranslationX(0.0f);
toView.setTranslationY(0.0f);
toView.setScaleX(1.0f);
toView.setScaleY(1.0f);
toView.setVisibility(View.VISIBLE);
toView.bringToFront();
// Show the content view
contentView.setVisibility(View.VISIBLE);
// Hide the search bar
mCb.onStateTransitionHideSearchBar();
dispatchOnLauncherTransitionPrepare(fromView, animated, false);
dispatchOnLauncherTransitionStart(fromView, animated, false);
dispatchOnLauncherTransitionEnd(fromView, animated, false);
dispatchOnLauncherTransitionPrepare(toView, animated, false);
dispatchOnLauncherTransitionStart(toView, animated, false);
dispatchOnLauncherTransitionEnd(toView, animated, false);
}
}
/**
* Starts and animation to the workspace from the apps view.
*/
private void startAnimationToWorkspaceFromAllApps(final Launcher.State fromState,
final Workspace.State toWorkspaceState, final boolean animated,
final Runnable onCompleteRunnable) {
AppsContainerView appsView = mLauncher.getAppsView();
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
int[] mAllAppsToPanelDelta;
@Override
public void onRevealViewVisible(View revealView, View contentView,
View allAppsButtonView) {
// Get the y delta between the center of the page and the center of the all apps
// button
mAllAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
allAppsButtonView, null);
}
@Override
public float getMaterialRevealViewFinalXDrift(View revealView) {
return mAllAppsToPanelDelta[0];
}
@Override
public float getMaterialRevealViewFinalYDrift(View revealView) {
return mAllAppsToPanelDelta[1];
}
@Override
float getMaterialRevealViewFinalAlpha(View revealView) {
// No alpha anim from all apps
return 1f;
}
@Override
float getMaterialRevealViewStartFinalRadius() {
int allAppsButtonSize = LauncherAppState.getInstance().
getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize;
return allAppsButtonSize / 2;
}
@Override
public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
final View revealView, final View allAppsButtonView) {
return new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animation) {
// We set the alpha instead of visibility to ensure that the focus does not
// get taken from the all apps view
allAppsButtonView.setVisibility(View.VISIBLE);
allAppsButtonView.setAlpha(0f);
}
public void onAnimationEnd(Animator animation) {
// Hide the reveal view
revealView.setVisibility(View.INVISIBLE);
// Show the all apps button, and focus it
allAppsButtonView.setAlpha(1f);
}
};
}
};
startAnimationToWorkspaceFromOverlay(toWorkspaceState, appsView, appsView.getContentView(),
appsView.getRevealView(), null /* pageIndicatorsView */, animated,
onCompleteRunnable, cb);
}
/**
* Starts and animation to the workspace from the widgets view.
*/
private void startAnimationToWorkspaceFromWidgets(final Launcher.State fromState,
final Workspace.State toWorkspaceState, final boolean animated,
final Runnable onCompleteRunnable) {
AppsCustomizeTabHost widgetsView = mLauncher.getWidgetsView();
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
@Override
public void onRevealViewVisible(View revealView, View contentView, View allAppsButtonView) {
AppsCustomizePagedView pagedView = ((AppsCustomizePagedView) contentView);
// Hide the real page background, and swap in the fake one
pagedView.stopScrolling();
pagedView.setPageBackgroundsVisible(false);
revealView.setBackground(mLauncher.getDrawable(R.drawable.quantum_panel_dark));
// Hide the side pages of the Widget tray to avoid some ugly edge cases
final View currentPage = pagedView.getPageAt(pagedView.getNextPage());
int count = pagedView.getChildCount();
for (int i = 0; i < count; i++) {
View child = pagedView.getChildAt(i);
if (child != currentPage) {
child.setVisibility(View.INVISIBLE);
}
}
}
@Override
public void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) {
AppsCustomizePagedView pagedView = ((AppsCustomizePagedView) contentView);
// Show the real page background and force-update the page
pagedView.setPageBackgroundsVisible(true);
pagedView.setCurrentPage(pagedView.getNextPage());
pagedView.updateCurrentPageScroll();
// Unhide the side pages
int count = pagedView.getChildCount();
for (int i = 0; i < count; i++) {
View child = pagedView.getChildAt(i);
child.setVisibility(View.VISIBLE);
}
}
@Override
public float getMaterialRevealViewFinalYDrift(View revealView) {
return revealView.getMeasuredHeight() / 2;
}
@Override
float getMaterialRevealViewFinalAlpha(View revealView) {
return 0.4f;
}
@Override
public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
final View revealView, final View allAppsButtonView) {
return new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
// Hide the reveal view
revealView.setVisibility(View.INVISIBLE);
}
};
}
};
startAnimationToWorkspaceFromOverlay(toWorkspaceState, widgetsView,
widgetsView.getContentView(), widgetsView.getRevealView(),
widgetsView.getPageIndicators(), animated, onCompleteRunnable, cb);
}
/**
* Creates and starts a new animation to the workspace.
*/
private void startAnimationToWorkspaceFromOverlay(final Workspace.State toWorkspaceState,
final View fromView, final View contentView, final View revealView,
final View pageIndicatorsView, final boolean animated,
final Runnable onCompleteRunnable, final PrivateTransitionCallbacks pCb) {
final Resources res = mLauncher.getResources();
final boolean material = Utilities.isLmpOrAbove();
final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
final int itemsAlphaStagger =
res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger);
final View allAppsButtonView = mLauncher.getAllAppsButton();
final View toView = mLauncher.getWorkspace();
final HashMap<View, Integer> layerViews = new HashMap<>();
// If for some reason our views aren't initialized, don't animate
boolean initialized = allAppsButtonView != null;
// Cancel the current animation
cancelAnimation();
// Create the workspace animation.
// NOTE: this call apparently also sets the state for the workspace if !animated
Animator workspaceAnim = mLauncher.getWorkspace().getChangeStateAnimation(
toWorkspaceState, animated, layerViews);
if (animated && initialized) {
mStateAnimation = LauncherAnimUtils.createAnimatorSet();
// Play the workspace animation
if (workspaceAnim != null) {
mStateAnimation.play(workspaceAnim);
}
// hideAppsCustomizeHelper is called in some cases when it is already hidden
// don't perform all these no-op animations. In particularly, this was causing
// the all-apps button to pop in and out.
if (fromView.getVisibility() == View.VISIBLE) {
int width = revealView.getMeasuredWidth();
int height = revealView.getMeasuredHeight();
float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
revealView.setVisibility(View.VISIBLE);
revealView.setAlpha(1f);
revealView.setTranslationY(0);
layerViews.put(revealView, BUILD_AND_SET_LAYER);
pCb.onRevealViewVisible(revealView, contentView, allAppsButtonView);
// Calculate the final animation values
final float revealViewToXDrift;
final float revealViewToYDrift;
if (material) {
revealViewToYDrift = pCb.getMaterialRevealViewFinalYDrift(revealView);
revealViewToXDrift = pCb.getMaterialRevealViewFinalXDrift(revealView);
} else {
revealViewToYDrift = 2 * height / 3;
revealViewToXDrift = 0;
}
// The vertical motion of the apps panel should be delayed by one frame
// from the conceal animation in order to give the right feel. We correspondingly
// shorten the duration so that the slide and conceal end at the same time.
TimeInterpolator decelerateInterpolator = material ?
new LogDecelerateInterpolator(100, 0) :
new DecelerateInterpolator(1f);
ObjectAnimator panelDriftY = LauncherAnimUtils.ofFloat(revealView, "translationY",
0, revealViewToYDrift);
panelDriftY.setDuration(revealDuration - SINGLE_FRAME_DELAY);
panelDriftY.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
panelDriftY.setInterpolator(decelerateInterpolator);
mStateAnimation.play(panelDriftY);
ObjectAnimator panelDriftX = LauncherAnimUtils.ofFloat(revealView, "translationX",
0, revealViewToXDrift);
panelDriftX.setDuration(revealDuration - SINGLE_FRAME_DELAY);
panelDriftX.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
panelDriftX.setInterpolator(decelerateInterpolator);
mStateAnimation.play(panelDriftX);
// Setup animation for the reveal panel alpha
final float revealViewToAlpha = !material ? 0f :
pCb.getMaterialRevealViewFinalAlpha(revealView);
if (revealViewToAlpha != 1f) {
ObjectAnimator panelAlpha = LauncherAnimUtils.ofFloat(revealView, "alpha",
1f, revealViewToAlpha);
panelAlpha.setDuration(material ? revealDuration : 150);
panelAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY);
panelAlpha.setInterpolator(decelerateInterpolator);
mStateAnimation.play(panelAlpha);
}
// Setup the animation for the content view
layerViews.put(contentView, BUILD_AND_SET_LAYER);
// Create the individual animators
ObjectAnimator pageDrift = LauncherAnimUtils.ofFloat(contentView, "translationY",
0, revealViewToYDrift);
contentView.setTranslationY(0);
pageDrift.setDuration(revealDuration - SINGLE_FRAME_DELAY);
pageDrift.setInterpolator(decelerateInterpolator);
pageDrift.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
mStateAnimation.play(pageDrift);
contentView.setAlpha(1f);
ObjectAnimator itemsAlpha = LauncherAnimUtils.ofFloat(contentView, "alpha", 1f, 0f);
itemsAlpha.setDuration(100);
itemsAlpha.setInterpolator(decelerateInterpolator);
mStateAnimation.play(itemsAlpha);
// Setup the page indicators animation
if (pageIndicatorsView != null) {
pageIndicatorsView.setAlpha(1f);
ObjectAnimator indicatorsAlpha =
LauncherAnimUtils.ofFloat(pageIndicatorsView, "alpha", 0f);
indicatorsAlpha.setDuration(revealDuration);
indicatorsAlpha.setInterpolator(new DecelerateInterpolator(1.5f));
mStateAnimation.play(indicatorsAlpha);
}
if (material) {
// Animate the all apps button
float finalRadius = pCb.getMaterialRevealViewStartFinalRadius();
AnimatorListenerAdapter listener =
pCb.getMaterialRevealViewAnimatorListener(revealView, allAppsButtonView);
Animator reveal =
LauncherAnimUtils.createCircularReveal(revealView, width / 2,
height / 2, revealRadius, finalRadius);
reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
reveal.setDuration(revealDuration);
reveal.setStartDelay(itemsAlphaStagger);
if (listener != null) {
reveal.addListener(listener);
}
mStateAnimation.play(reveal);
}
dispatchOnLauncherTransitionPrepare(fromView, animated, true);
dispatchOnLauncherTransitionPrepare(toView, animated, true);
}
mStateAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
fromView.setVisibility(View.GONE);
dispatchOnLauncherTransitionEnd(fromView, animated, true);
dispatchOnLauncherTransitionEnd(toView, animated, true);
// Run any queued runnables
if (onCompleteRunnable != null) {
onCompleteRunnable.run();
}
// Animation complete callback
pCb.onAnimationComplete(revealView, contentView, allAppsButtonView);
// Disable all necessary layers
for (View v : layerViews.keySet()) {
if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
v.setLayerType(View.LAYER_TYPE_NONE, null);
}
}
// Reset page transforms
if (contentView != null) {
contentView.setTranslationX(0);
contentView.setTranslationY(0);
contentView.setAlpha(1);
}
// This can hold unnecessary references to views.
mStateAnimation = null;
}
});
final AnimatorSet stateAnimation = mStateAnimation;
final Runnable startAnimRunnable = new Runnable() {
public void run() {
// Check that mStateAnimation hasn't changed while
// we waited for a layout/draw pass
if (mStateAnimation != stateAnimation)
return;
dispatchOnLauncherTransitionStart(fromView, animated, false);
dispatchOnLauncherTransitionStart(toView, animated, false);
// Enable all necessary layers
for (View v : layerViews.keySet()) {
if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
if (Utilities.isLmpOrAbove()) {
v.buildLayer();
}
}
mStateAnimation.start();
}
};
fromView.post(startAnimRunnable);
} else {
fromView.setVisibility(View.GONE);
dispatchOnLauncherTransitionPrepare(fromView, animated, true);
dispatchOnLauncherTransitionStart(fromView, animated, true);
dispatchOnLauncherTransitionEnd(fromView, animated, true);
dispatchOnLauncherTransitionPrepare(toView, animated, true);
dispatchOnLauncherTransitionStart(toView, animated, true);
dispatchOnLauncherTransitionEnd(toView, animated, true);
// Run any queued runnables
if (onCompleteRunnable != null) {
onCompleteRunnable.run();
}
}
}
/**
* Dispatches the prepare-transition event to suitable views.
*/
void dispatchOnLauncherTransitionPrepare(View v, boolean animated, boolean toWorkspace) {
if (v instanceof LauncherTransitionable) {
((LauncherTransitionable) v).onLauncherTransitionPrepare(mLauncher, animated,
toWorkspace);
}
}
/**
* Dispatches the start-transition event to suitable views.
*/
void dispatchOnLauncherTransitionStart(View v, boolean animated, boolean toWorkspace) {
if (v instanceof LauncherTransitionable) {
((LauncherTransitionable) v).onLauncherTransitionStart(mLauncher, animated,
toWorkspace);
}
// Update the workspace transition step as well
dispatchOnLauncherTransitionStep(v, 0f);
}
/**
* Dispatches the step-transition event to suitable views.
*/
void dispatchOnLauncherTransitionStep(View v, float t) {
if (v instanceof LauncherTransitionable) {
((LauncherTransitionable) v).onLauncherTransitionStep(mLauncher, t);
}
}
/**
* Dispatches the end-transition event to suitable views.
*/
void dispatchOnLauncherTransitionEnd(View v, boolean animated, boolean toWorkspace) {
if (v instanceof LauncherTransitionable) {
((LauncherTransitionable) v).onLauncherTransitionEnd(mLauncher, animated,
toWorkspace);
}
// Update the workspace transition step as well
dispatchOnLauncherTransitionStep(v, 1f);
}
/**
* Cancels the current animation.
*/
private void cancelAnimation() {
if (mStateAnimation != null) {
mStateAnimation.setDuration(0);
mStateAnimation.cancel();
mStateAnimation = null;
}
}
}
@@ -109,7 +109,7 @@ public abstract class PagedViewWithDraggableItems extends PagedView
// Return early if we are still animating the pages
if (mNextPage != INVALID_PAGE) return false;
// When we have exited all apps or are in transition, disregard long clicks
if (!mLauncher.isAllAppsVisible() ||
if (!mLauncher.isWidgetsViewVisible() ||
mLauncher.getWorkspace().isSwitchingState()) return false;
// Return if global dragging is not enabled
if (!mLauncher.isDraggingEnabled()) return false;
@@ -131,8 +131,8 @@ public class WidgetPreviewLoader {
private final PaintCache mDefaultAppWidgetPreviewPaint = new PaintCache();
private final BitmapFactoryOptionsCache mCachedBitmapFactoryOptions = new BitmapFactoryOptionsCache();
private final HashMap<String, WeakReference<Bitmap>> mLoadedPreviews = new HashMap<String, WeakReference<Bitmap>>();
private final ArrayList<SoftReference<Bitmap>> mUnusedBitmaps = new ArrayList<SoftReference<Bitmap>>();
private final HashMap<String, WeakReference<Bitmap>> mLoadedPreviews = new HashMap<>();
private final ArrayList<SoftReference<Bitmap>> mUnusedBitmaps = new ArrayList<>();
private final Context mContext;
private final int mAppIconSize;
@@ -0,0 +1,88 @@
package com.android.launcher3;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
class SectionedWidgetsRow {
String section;
List<List<Object>> widgets;
public SectionedWidgetsRow(String sc) {
section = sc;
}
}
class SectionedWidgetsAlgorithm {
public List<SectionedWidgetsRow> computeSectionedWidgetRows(List<Object> sortedWidgets,
int widgetsPerRow) {
List<SectionedWidgetsRow> rows = new ArrayList<>();
LinkedHashMap<String, List<Object>> sections = computeSectionedApps(sortedWidgets);
for (Map.Entry<String, List<Object>> sectionEntry : sections.entrySet()) {
String section = sectionEntry.getKey();
SectionedWidgetsRow row = new SectionedWidgetsRow(section);
List<Object> widgets = sectionEntry.getValue();
int numRows = (int) Math.ceil((float) widgets.size() / widgetsPerRow);
for (int i = 0; i < numRows; i++) {
List<Object> widgetsInRow = new ArrayList<>();
int offset = i * widgetsPerRow;
for (int j = 0; j < widgetsPerRow; j++) {
widgetsInRow.add(widgets.get(offset + j));
}
row.widgets.add(widgetsInRow);
}
}
return rows;
}
private LinkedHashMap<String, List<Object>> computeSectionedApps(List<Object> sortedWidgets) {
LinkedHashMap<String, List<Object>> sections = new LinkedHashMap<>();
for (Object info : sortedWidgets) {
String section = getSection(info);
List<Object> sectionedWidgets = sections.get(section);
if (sectionedWidgets == null) {
sectionedWidgets = new ArrayList<>();
sections.put(section, sectionedWidgets);
}
sectionedWidgets.add(info);
}
return sections;
}
private String getSection(Object widgetOrShortcut) {
return "UNKNOWN";
}
}
/**
* The widgets list view container.
*/
public class WidgetsContainerView extends FrameLayout {
public WidgetsContainerView(Context context) {
this(context, null);
}
public WidgetsContainerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onFinishInflate() {
}
}
+40 -27
View File
@@ -1528,7 +1528,7 @@ public class Workspace extends SmoothPagedView
@Override
public void announceForAccessibility(CharSequence text) {
// Don't announce if apps is on top of us.
if (!mLauncher.isAllAppsVisible()) {
if (!mLauncher.isAppsViewVisible()) {
super.announceForAccessibility(text);
}
}
@@ -1816,7 +1816,7 @@ public class Workspace extends SmoothPagedView
@Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
if (!mLauncher.isAllAppsVisible()) {
if (!mLauncher.isAppsViewVisible()) {
final Folder openFolder = getOpenFolder();
if (openFolder != null) {
return openFolder.requestFocus(direction, previouslyFocusedRect);
@@ -1837,7 +1837,7 @@ public class Workspace extends SmoothPagedView
@Override
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
if (!mLauncher.isAllAppsVisible()) {
if (!mLauncher.isAppsViewVisible()) {
final Folder openFolder = getOpenFolder();
if (openFolder != null) {
openFolder.addFocusables(views, direction);
@@ -2046,8 +2046,7 @@ public class Workspace extends SmoothPagedView
// If this is a text view, use its drawable instead
if (v instanceof TextView) {
TextView tv = (TextView) v;
Drawable d = tv.getCompoundDrawables()[1];
Drawable d = getTextViewIcon((TextView) v);
Rect bounds = getDrawableBounds(d);
bmpWidth = bounds.width();
bmpHeight = bounds.height();
@@ -2348,7 +2347,7 @@ public class Workspace extends SmoothPagedView
cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);
} else {
if (layerViews != null) {
layerViews.put(cl, Launcher.BUILD_LAYER);
layerViews.put(cl, LauncherStateTransitionAnimation.BUILD_LAYER);
}
if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {
LauncherViewPropertyAnimator alphaAnim =
@@ -2400,8 +2399,8 @@ public class Workspace extends SmoothPagedView
if (layerViews != null) {
// If layerViews is not null, we add these views, and indicate that
// the caller can manage layer state.
layerViews.put(hotseat, Launcher.BUILD_AND_SET_LAYER);
layerViews.put(overviewPanel, Launcher.BUILD_AND_SET_LAYER);
layerViews.put(hotseat, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
layerViews.put(overviewPanel, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
} else {
// Otherwise let the animator handle layer management.
hotseatAlpha.withLayer();
@@ -2430,7 +2429,7 @@ public class Workspace extends SmoothPagedView
if (layerViews != null) {
// If layerViews is not null, we add these views, and indicate that
// the caller can manage layer state.
layerViews.put(searchBar, Launcher.BUILD_AND_SET_LAYER);
layerViews.put(searchBar, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
} else {
// Otherwise let the animator handle layer management.
searchBarAlpha.withLayer();
@@ -2583,6 +2582,19 @@ public class Workspace extends SmoothPagedView
return this;
}
/**
* Returns the drawable for the given text view.
*/
public static Drawable getTextViewIcon(TextView tv) {
final Drawable[] drawables = tv.getCompoundDrawables();
for (int i = 0; i < drawables.length; i++) {
if (drawables[i] != null) {
return drawables[i];
}
}
return null;
}
/**
* Draw the View v into the given Canvas.
*
@@ -2598,7 +2610,7 @@ public class Workspace extends SmoothPagedView
destCanvas.save();
if (v instanceof TextView) {
Drawable d = ((TextView) v).getCompoundDrawables()[1];
Drawable d = getTextViewIcon((TextView) v);
Rect bounds = getDrawableBounds(d);
clipRect.set(0, 0, bounds.width() + padding, bounds.height() + padding);
destCanvas.translate(padding / 2 - bounds.left, padding / 2 - bounds.top);
@@ -2635,7 +2647,7 @@ public class Workspace extends SmoothPagedView
int padding = expectedPadding.get();
if (v instanceof TextView) {
Drawable d = ((TextView) v).getCompoundDrawables()[1];
Drawable d = getTextViewIcon((TextView) v);
Rect bounds = getDrawableBounds(d);
b = Bitmap.createBitmap(bounds.width() + padding,
bounds.height() + padding, Bitmap.Config.ARGB_8888);
@@ -2716,11 +2728,12 @@ public class Workspace extends SmoothPagedView
beginDragShared(child, this, accessible);
}
public void beginDragShared(View child, DragSource source) {
beginDragShared(child, source, false);
public void beginDragShared(View child, DragSource source, boolean accessible) {
beginDragShared(child, new Point(), source, accessible);
}
public void beginDragShared(View child, DragSource source, boolean accessible) {
public void beginDragShared(View child, Point relativeTouchPos, DragSource source,
boolean accessible) {
child.clearFocus();
child.setPressed(false);
@@ -2745,11 +2758,23 @@ public class Workspace extends SmoothPagedView
Point dragVisualizeOffset = null;
Rect dragRect = null;
if (child instanceof BubbleTextView) {
BubbleTextView icon = (BubbleTextView) child;
int iconSize = grid.iconSizePx;
int top = child.getPaddingTop();
int left = (bmpWidth - iconSize) / 2;
int right = left + iconSize;
int bottom = top + iconSize;
if (icon.isLayoutHorizontal()) {
// If the layout is horizontal, then if we are just picking up the icon, then just
// use the child position since the icon is top-left aligned. Otherwise, offset
// the drag layer position horizontally so that the icon is under the current
// touch position.
if (icon.getIcon().getBounds().contains(relativeTouchPos.x, relativeTouchPos.y)) {
dragLayerX = Math.round(mTempXY[0]);
} else {
dragLayerX = Math.round(mTempXY[0] + relativeTouchPos.x - (bmpWidth / 2));
}
}
dragLayerY += top;
// Note: The drag region is used to calculate drag layer offsets, but the
// dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
@@ -2831,18 +2856,6 @@ public class Workspace extends SmoothPagedView
tmpB.recycle();
}
void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, long screenId,
int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) {
View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info);
final int[] cellXY = new int[2];
target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY);
addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1, insertAtFirst);
LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, cellXY[0],
cellXY[1]);
}
public boolean transitionStateShouldAllowDrop() {
return ((!isSwitchingState() || mTransitionProgress > 0.5f) &&
(mState == State.NORMAL || mState == State.SPRING_LOADED));
@@ -4769,7 +4782,7 @@ public class Workspace extends SmoothPagedView
updates.contains(info)) {
ShortcutInfo si = (ShortcutInfo) info;
BubbleTextView shortcut = (BubbleTextView) v;
boolean oldPromiseState = shortcut.getCompoundDrawables()[1]
boolean oldPromiseState = getTextViewIcon(shortcut)
instanceof PreloadIconDrawable;
shortcut.applyFromShortcutInfo(si, mIconCache, true,
si.isPromise() != oldPromiseState);