OSDN Git Service

18fe8ef868528c3c03ba11663be3ca90ca0d4df2
[android-x86/packages-apps-Launcher3.git] / src / com / android / launcher3 / LauncherClings.java
1 /*
2  * Copyright (C) 2008 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;
18
19 import android.animation.ObjectAnimator;
20 import android.animation.PropertyValuesHolder;
21 import android.annotation.TargetApi;
22 import android.app.ActivityManager;
23 import android.content.Context;
24 import android.content.SharedPreferences;
25 import android.graphics.drawable.Drawable;
26 import android.os.Build;
27 import android.os.Bundle;
28 import android.os.UserManager;
29 import android.provider.Settings;
30 import android.view.LayoutInflater;
31 import android.view.View;
32 import android.view.View.OnClickListener;
33 import android.view.View.OnLongClickListener;
34 import android.view.ViewGroup;
35 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
36 import android.view.accessibility.AccessibilityManager;
37
38 import com.android.launcher3.util.Thunk;
39
40 class LauncherClings implements OnClickListener {
41     private static final String MIGRATION_CLING_DISMISSED_KEY = "cling_gel.migration.dismissed";
42     private static final String WORKSPACE_CLING_DISMISSED_KEY = "cling_gel.workspace.dismissed";
43
44     private static final String TAG_CROP_TOP_AND_SIDES = "crop_bg_top_and_sides";
45
46     private static final int SHOW_CLING_DURATION = 250;
47     private static final int DISMISS_CLING_DURATION = 200;
48
49     // New Secure Setting in L
50     private static final String SKIP_FIRST_USE_HINTS = "skip_first_use_hints";
51
52     @Thunk Launcher mLauncher;
53     private LayoutInflater mInflater;
54     @Thunk boolean mIsVisible;
55
56     /** Ctor */
57     public LauncherClings(Launcher launcher) {
58         mLauncher = launcher;
59         mInflater = LayoutInflater.from(mLauncher);
60     }
61
62     @Override
63     public void onClick(View v) {
64         int id = v.getId();
65         if (id == R.id.cling_dismiss_migration_use_default) {
66             // Disable the migration cling
67             dismissMigrationCling();
68         } else if (id == R.id.cling_dismiss_migration_copy_apps) {
69             // Copy the shortcuts from the old database
70             LauncherModel model = mLauncher.getModel();
71             model.resetLoadedState(false, true);
72             model.startLoader(PagedView.INVALID_RESTORE_PAGE,
73                     LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE
74                             | LauncherModel.LOADER_FLAG_MIGRATE_SHORTCUTS);
75             // Set the flag to skip the folder cling
76             String spKey = LauncherAppState.getSharedPreferencesKey();
77             SharedPreferences sp = mLauncher.getSharedPreferences(spKey, Context.MODE_PRIVATE);
78             SharedPreferences.Editor editor = sp.edit();
79             editor.putBoolean(Launcher.USER_HAS_MIGRATED, true);
80             editor.apply();
81             // Disable the migration cling
82             dismissMigrationCling();
83         } else if (id == R.id.cling_dismiss_longpress_info) {
84             dismissLongPressCling();
85         }
86     }
87
88     /**
89      * Shows the migration cling.
90      *
91      * This flow is mutually exclusive with showFirstRunCling, and only runs if this Launcher
92      * package was not preinstalled and there exists a db to migrate from.
93      */
94     public void showMigrationCling() {
95         mIsVisible = true;
96         mLauncher.hideWorkspaceSearchAndHotseat();
97
98         ViewGroup root = (ViewGroup) mLauncher.findViewById(R.id.launcher);
99         View inflated = mInflater.inflate(R.layout.migration_cling, root);
100         inflated.findViewById(R.id.cling_dismiss_migration_copy_apps).setOnClickListener(this);
101         inflated.findViewById(R.id.cling_dismiss_migration_use_default).setOnClickListener(this);
102     }
103
104     private void dismissMigrationCling() {
105         mLauncher.showWorkspaceSearchAndHotseat();
106         Runnable dismissCb = new Runnable() {
107             public void run() {
108                 Runnable cb = new Runnable() {
109                     public void run() {
110                         // Show the longpress cling next
111                         showLongPressCling(false);
112                     }
113                 };
114                 dismissCling(mLauncher.findViewById(R.id.migration_cling), cb,
115                         MIGRATION_CLING_DISMISSED_KEY, DISMISS_CLING_DURATION);
116             }
117         };
118         mLauncher.getWorkspace().post(dismissCb);
119     }
120
121     public void showLongPressCling(boolean showWelcome) {
122         mIsVisible = true;
123         ViewGroup root = (ViewGroup) mLauncher.findViewById(R.id.launcher);
124         View cling = mInflater.inflate(R.layout.longpress_cling, root, false);
125
126         cling.setOnLongClickListener(new OnLongClickListener() {
127
128             @Override
129             public boolean onLongClick(View v) {
130                 mLauncher.showOverviewMode(true);
131                 dismissLongPressCling();
132                 return true;
133             }
134         });
135
136         final ViewGroup content = (ViewGroup) cling.findViewById(R.id.cling_content);
137         mInflater.inflate(showWelcome ? R.layout.longpress_cling_welcome_content
138                 : R.layout.longpress_cling_content, content);
139         content.findViewById(R.id.cling_dismiss_longpress_info).setOnClickListener(this);
140
141         if (TAG_CROP_TOP_AND_SIDES.equals(content.getTag())) {
142             Drawable bg = new BorderCropDrawable(mLauncher.getResources().getDrawable(R.drawable.cling_bg),
143                     true, true, true, false);
144             content.setBackground(bg);
145         }
146
147         root.addView(cling);
148
149         if (showWelcome) {
150             // This is the first cling being shown. No need to animate.
151             return;
152         }
153
154         // Animate
155         content.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
156
157             @Override
158             public void onGlobalLayout() {
159                 content.getViewTreeObserver().removeOnGlobalLayoutListener(this);
160
161                 ObjectAnimator anim;
162                 if (TAG_CROP_TOP_AND_SIDES.equals(content.getTag())) {
163                     content.setTranslationY(-content.getMeasuredHeight());
164                     anim = LauncherAnimUtils.ofFloat(content, "translationY", 0);
165                 } else {
166                     content.setScaleX(0);
167                     content.setScaleY(0);
168                     PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1);
169                     PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1);
170                     anim = LauncherAnimUtils.ofPropertyValuesHolder(content, scaleX, scaleY);
171                 }
172
173                 anim.setDuration(SHOW_CLING_DURATION);
174                 anim.setInterpolator(new LogDecelerateInterpolator(100, 0));
175                 anim.start();
176             }
177         });
178     }
179
180     @Thunk void dismissLongPressCling() {
181         Runnable dismissCb = new Runnable() {
182             public void run() {
183                 dismissCling(mLauncher.findViewById(R.id.longpress_cling), null,
184                         WORKSPACE_CLING_DISMISSED_KEY, DISMISS_CLING_DURATION);
185             }
186         };
187         mLauncher.getWorkspace().post(dismissCb);
188     }
189
190     /** Hides the specified Cling */
191     @Thunk void dismissCling(final View cling, final Runnable postAnimationCb,
192                               final String flag, int duration) {
193         // To catch cases where siblings of top-level views are made invisible, just check whether
194         // the cling is directly set to GONE before dismissing it.
195         if (cling != null && cling.getVisibility() != View.GONE) {
196             final Runnable cleanUpClingCb = new Runnable() {
197                 public void run() {
198                     cling.setVisibility(View.GONE);
199                     mLauncher.getSharedPrefs().edit()
200                         .putBoolean(flag, true)
201                         .apply();
202                     mIsVisible = false;
203                     if (postAnimationCb != null) {
204                         postAnimationCb.run();
205                     }
206                 }
207             };
208             if (duration <= 0) {
209                 cleanUpClingCb.run();
210             } else {
211                 cling.animate().alpha(0).setDuration(duration).withEndAction(cleanUpClingCb);
212             }
213         }
214     }
215
216     public boolean isVisible() {
217         return mIsVisible;
218     }
219
220     /** Returns whether the clings are enabled or should be shown */
221     @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
222     private boolean areClingsEnabled() {
223         // disable clings when running in a test harness
224         if(ActivityManager.isRunningInTestHarness()) return false;
225
226         // Disable clings for accessibility when explore by touch is enabled
227         final AccessibilityManager a11yManager = (AccessibilityManager) mLauncher.getSystemService(
228                 Launcher.ACCESSIBILITY_SERVICE);
229         if (a11yManager.isTouchExplorationEnabled()) {
230             return false;
231         }
232
233         // Restricted secondary users (child mode) will potentially have very few apps
234         // seeded when they start up for the first time. Clings won't work well with that
235         if (Utilities.ATLEAST_JB_MR2) {
236             UserManager um = (UserManager) mLauncher.getSystemService(Context.USER_SERVICE);
237             Bundle restrictions = um.getUserRestrictions();
238             if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) {
239                 return false;
240             }
241         }
242         if (Settings.Secure.getInt(mLauncher.getContentResolver(), SKIP_FIRST_USE_HINTS, 0)
243                 == 1) {
244             return false;
245         }
246         return true;
247     }
248
249     public boolean shouldShowFirstRunOrMigrationClings() {
250         SharedPreferences sharedPrefs = mLauncher.getSharedPrefs();
251         return areClingsEnabled() &&
252             !sharedPrefs.getBoolean(WORKSPACE_CLING_DISMISSED_KEY, false) &&
253             !sharedPrefs.getBoolean(MIGRATION_CLING_DISMISSED_KEY, false);
254     }
255
256     public static void synchonouslyMarkFirstRunClingDismissed(Context ctx) {
257         SharedPreferences prefs = ctx.getSharedPreferences(
258                 LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);
259         SharedPreferences.Editor editor = prefs.edit();
260         editor.putBoolean(WORKSPACE_CLING_DISMISSED_KEY, true);
261         editor.commit();
262     }
263 }