Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.launcher3.widget;
     18 
     19 import android.content.Context;
     20 import android.content.pm.LauncherApps;
     21 import android.graphics.Point;
     22 import android.support.v7.widget.LinearLayoutManager;
     23 import android.util.AttributeSet;
     24 import android.util.Log;
     25 import android.view.LayoutInflater;
     26 import android.view.View;
     27 import android.view.ViewGroup;
     28 import android.widget.Toast;
     29 
     30 import com.android.launcher3.BaseContainerView;
     31 import com.android.launcher3.DeleteDropTarget;
     32 import com.android.launcher3.DragSource;
     33 import com.android.launcher3.DropTarget.DragObject;
     34 import com.android.launcher3.ItemInfo;
     35 import com.android.launcher3.Launcher;
     36 import com.android.launcher3.LauncherAppState;
     37 import com.android.launcher3.R;
     38 import com.android.launcher3.Utilities;
     39 import com.android.launcher3.compat.AlphabeticIndexCompat;
     40 import com.android.launcher3.dragndrop.DragOptions;
     41 import com.android.launcher3.folder.Folder;
     42 import com.android.launcher3.model.PackageItemInfo;
     43 import com.android.launcher3.model.WidgetItem;
     44 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
     45 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
     46 import com.android.launcher3.util.MultiHashMap;
     47 import com.android.launcher3.util.PackageUserKey;
     48 import com.android.launcher3.util.Thunk;
     49 
     50 import java.util.List;
     51 
     52 /**
     53  * The widgets list view container.
     54  */
     55 public class WidgetsContainerView extends BaseContainerView
     56         implements View.OnLongClickListener, View.OnClickListener, DragSource {
     57     private static final String TAG = "WidgetsContainerView";
     58     private static final boolean LOGD = false;
     59 
     60     /* Global instances that are used inside this container. */
     61     @Thunk Launcher mLauncher;
     62 
     63     /* Recycler view related member variables */
     64     private WidgetsRecyclerView mRecyclerView;
     65     private WidgetsListAdapter mAdapter;
     66 
     67     /* Touch handling related member variables. */
     68     private Toast mWidgetInstructionToast;
     69 
     70     public WidgetsContainerView(Context context) {
     71         this(context, null);
     72     }
     73 
     74     public WidgetsContainerView(Context context, AttributeSet attrs) {
     75         this(context, attrs, 0);
     76     }
     77 
     78     public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
     79         super(context, attrs, defStyleAttr);
     80         mLauncher = Launcher.getLauncher(context);
     81         LauncherAppState apps = LauncherAppState.getInstance(context);
     82         mAdapter = new WidgetsListAdapter(context, LayoutInflater.from(context),
     83                 apps.getWidgetCache(), new AlphabeticIndexCompat(context), this, this,
     84                 new WidgetsDiffReporter(apps.getIconCache()));
     85         mAdapter.setNotifyListener();
     86         if (LOGD) {
     87             Log.d(TAG, "WidgetsContainerView constructor");
     88         }
     89     }
     90 
     91     @Override
     92     public View getTouchDelegateTargetView() {
     93         return mRecyclerView;
     94     }
     95 
     96     @Override
     97     protected void onFinishInflate() {
     98         super.onFinishInflate();
     99         mRecyclerView = (WidgetsRecyclerView) getContentView().findViewById(R.id.widgets_list_view);
    100         mRecyclerView.setAdapter(mAdapter);
    101         mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
    102     }
    103 
    104     //
    105     // Returns views used for launcher transitions.
    106     //
    107 
    108     public void scrollToTop() {
    109         mRecyclerView.scrollToPosition(0);
    110     }
    111 
    112     //
    113     // Touch related handling.
    114     //
    115 
    116     @Override
    117     public void onClick(View v) {
    118         // When we have exited widget tray or are in transition, disregard clicks
    119         if (!mLauncher.isWidgetsViewVisible()
    120                 || mLauncher.getWorkspace().isSwitchingState()
    121                 || !(v instanceof WidgetCell)) return;
    122 
    123         handleClick();
    124     }
    125 
    126     public void handleClick() {
    127         // Let the user know that they have to long press to add a widget
    128         if (mWidgetInstructionToast != null) {
    129             mWidgetInstructionToast.cancel();
    130         }
    131 
    132         CharSequence msg = Utilities.wrapForTts(
    133                 getContext().getText(R.string.long_press_widget_to_add),
    134                 getContext().getString(R.string.long_accessible_way_to_add));
    135         mWidgetInstructionToast = Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT);
    136         mWidgetInstructionToast.show();
    137     }
    138 
    139     @Override
    140     public boolean onLongClick(View v) {
    141         // When we have exited the widget tray, disregard long clicks
    142         if (!mLauncher.isWidgetsViewVisible()) return false;
    143         return handleLongClick(v);
    144     }
    145 
    146     public boolean handleLongClick(View v) {
    147         if (LOGD) {
    148             Log.d(TAG, String.format("onLongClick [v=%s]", v));
    149         }
    150         // When we  are in transition, disregard long clicks
    151         if (mLauncher.getWorkspace().isSwitchingState()) return false;
    152         // Return if global dragging is not enabled
    153         if (!mLauncher.isDraggingEnabled()) return false;
    154 
    155         return beginDragging(v);
    156     }
    157 
    158     private boolean beginDragging(View v) {
    159         if (v instanceof WidgetCell) {
    160             if (!beginDraggingWidget((WidgetCell) v)) {
    161                 return false;
    162             }
    163         } else {
    164             Log.e(TAG, "Unexpected dragging view: " + v);
    165         }
    166 
    167         // We don't enter spring-loaded mode if the drag has been cancelled
    168         if (mLauncher.getDragController().isDragging()) {
    169             // Go into spring loaded mode (must happen before we startDrag())
    170             mLauncher.enterSpringLoadedDragMode();
    171         }
    172 
    173         return true;
    174     }
    175 
    176     private boolean beginDraggingWidget(WidgetCell v) {
    177         // Get the widget preview as the drag representation
    178         WidgetImageView image = (WidgetImageView) v.findViewById(R.id.widget_preview);
    179 
    180         // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
    181         // we abort the drag.
    182         if (image.getBitmap() == null) {
    183             return false;
    184         }
    185 
    186         int[] loc = new int[2];
    187         mLauncher.getDragLayer().getLocationInDragLayer(image, loc);
    188 
    189         new PendingItemDragHelper(v).startDrag(
    190                 image.getBitmapBounds(), image.getBitmap().getWidth(), image.getWidth(),
    191                 new Point(loc[0], loc[1]), this, new DragOptions());
    192         return true;
    193     }
    194 
    195     //
    196     // Drag related handling methods that implement {@link DragSource} interface.
    197     //
    198 
    199     @Override
    200     public boolean supportsAppInfoDropTarget() {
    201         return true;
    202     }
    203 
    204     /*
    205      * Both this method and {@link #supportsFlingToDelete} has to return {@code false} for the
    206      * {@link DeleteDropTarget} to be invisible.)
    207      */
    208     @Override
    209     public boolean supportsDeleteDropTarget() {
    210         return false;
    211     }
    212 
    213     @Override
    214     public float getIntrinsicIconScaleFactor() {
    215         return 0;
    216     }
    217 
    218     @Override
    219     public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
    220             boolean success) {
    221         if (LOGD) {
    222             Log.d(TAG, "onDropCompleted");
    223         }
    224         if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
    225                 !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
    226             // Exit spring loaded mode if we have not successfully dropped or have not handled the
    227             // drop in Workspace
    228             mLauncher.exitSpringLoadedDragModeDelayed(true,
    229                     Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
    230         }
    231         mLauncher.unlockScreenOrientation(false);
    232 
    233         if (!success) {
    234             d.deferDragViewCleanupPostAnimation = false;
    235         }
    236     }
    237 
    238     /**
    239      * Initialize the widget data model.
    240      */
    241     public void setWidgets(MultiHashMap<PackageItemInfo, WidgetItem> model) {
    242         mAdapter.setWidgets(model);
    243 
    244         View loader = getContentView().findViewById(R.id.loader);
    245         if (loader != null) {
    246             ((ViewGroup) getContentView()).removeView(loader);
    247         }
    248     }
    249 
    250     public boolean isEmpty() {
    251         return mAdapter.getItemCount() == 0;
    252     }
    253 
    254     public List<WidgetItem> getWidgetsForPackageUser(PackageUserKey packageUserKey) {
    255         return mAdapter.copyWidgetsForPackageUser(packageUserKey);
    256     }
    257 
    258     @Override
    259     public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) {
    260         targetParent.containerType = ContainerType.WIDGETS;
    261     }
    262 }