Loading src/com/android/contacts/DynamicShortcuts.java +41 −10 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; import android.database.Cursor; Loading Loading @@ -56,8 +55,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import static com.android.contacts.common.list.ShortcutIntentBuilder.INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION; /** * This class creates and updates the dynamic shortcuts displayed on the Nexus launcher for the * Contacts app. Loading Loading @@ -95,17 +92,21 @@ public class DynamicShortcuts { private int mLongLabelMaxLength = LONG_LABEL_MAX_LENGTH; private final int mContentChangeMinUpdateDelay; private final int mContentChangeMaxUpdateDelay; private final JobScheduler mJobScheduler; public DynamicShortcuts(Context context) { this(context, context.getContentResolver(), (ShortcutManager) context.getSystemService(Context.SHORTCUT_SERVICE)); context.getSystemService(Context.SHORTCUT_SERVICE), (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE)); } @VisibleForTesting public DynamicShortcuts(Context context, ContentResolver contentResolver, ShortcutManager shortcutManager) { ShortcutManager shortcutManager, JobScheduler jobScheduler) { mContext = context; mContentResolver = contentResolver; mShortcutManager = shortcutManager; mJobScheduler = jobScheduler; mContentChangeMinUpdateDelay = Flags.getInstance(mContext) .getInteger(Experiments.DYNAMIC_MIN_CONTENT_CHANGE_UPDATE_DELAY_MILLIS); mContentChangeMaxUpdateDelay = Flags.getInstance(mContext) Loading @@ -124,7 +125,11 @@ public class DynamicShortcuts { @VisibleForTesting void refresh() { mShortcutManager.setDynamicShortcuts(getStrequentShortcuts()); final List<ShortcutInfo> shortcuts = getStrequentShortcuts(); mShortcutManager.setDynamicShortcuts(shortcuts); if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "set dynamic shortcuts " + shortcuts); } updatePinned(); } Loading Loading @@ -154,6 +159,12 @@ public class DynamicShortcuts { } } if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "updating " + updates); Log.d(TAG, "enabling " + enable); Log.d(TAG, "disabling " + removedIds); } mShortcutManager.updateShortcuts(updates); mShortcutManager.enableShortcuts(enable); mShortcutManager.disableShortcuts(removedIds, Loading Loading @@ -332,7 +343,8 @@ public class DynamicShortcuts { return result; } private void handleFlagDisabled() { @VisibleForTesting void handleFlagDisabled() { mShortcutManager.removeAllDynamicShortcuts(); final List<ShortcutInfo> pinned = mShortcutManager.getPinnedShortcuts(); Loading @@ -342,6 +354,11 @@ public class DynamicShortcuts { } mShortcutManager.disableShortcuts(ids, mContext .getString(R.string.dynamic_shortcut_disabled_message)); if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "DynamicShortcuts have been removed."); } mJobScheduler.cancel(ContactsJobService.DYNAMIC_SHORTCUTS_JOB_ID); } @VisibleForTesting Loading @@ -356,12 +373,23 @@ public class DynamicShortcuts { JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)) .setTriggerContentUpdateDelay(mContentChangeMinUpdateDelay) .setTriggerContentMaxDelay(mContentChangeMaxUpdateDelay).build(); final JobScheduler scheduler = (JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE); scheduler.schedule(job); mJobScheduler.schedule(job); } public synchronized static void initialize(Context context) { if (Log.isLoggable(TAG, Log.DEBUG)) { final Flags flags = Flags.getInstance(context); Log.d(TAG, "DyanmicShortcuts.initialize\nVERSION >= N_MR1? " + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) + "\n" + Experiments.DYNAMIC_SHORTCUTS + " enabled? " + flags.getBoolean(Experiments.DYNAMIC_SHORTCUTS) + "\nisJobScheduled? " + isJobScheduled(context) + "\nminDelay=" + flags.getInteger(Experiments.DYNAMIC_MIN_CONTENT_CHANGE_UPDATE_DELAY_MILLIS) + "\nmaxDelay=" + flags.getInteger(Experiments.DYNAMIC_MAX_CONTENT_CHANGE_UPDATE_DELAY_MILLIS)); } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) return; final DynamicShortcuts shortcuts = new DynamicShortcuts(context); Loading Loading @@ -413,6 +441,9 @@ public class DynamicShortcuts { @Override protected void onPostExecute(Void aVoid) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "ShorcutUpdateTask.onPostExecute"); } // The shortcuts may have changed so update the job so that we are observing the // correct Uris mDynamicShortcuts.scheduleUpdateJob(); Loading tests/src/com/android/contacts/DynamicShortcutsTests.java +22 −8 Original line number Diff line number Diff line Loading @@ -52,14 +52,11 @@ import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; @TargetApi(Build.VERSION_CODES.N_MR1) @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N_MR1) // TODO: need to switch to android.support.test.runner.AndroidJUnitRunner for the @SdkSuppress // annotation to be respected. So for now we suppress this test to keep it from failing when run // by the build system. @Suppress @SmallTest public class DynamicShortcutsTests extends AndroidTestCase { Loading Loading @@ -120,8 +117,7 @@ public class DynamicShortcutsTests extends AndroidTestCase { when(mockShortcutManager.getPinnedShortcuts()).thenReturn( Collections.singletonList(shortcutFor(1l, "key1", "name1"))); final DynamicShortcuts sut = new DynamicShortcuts(getContext(), emptyResolver(), mockShortcutManager); final DynamicShortcuts sut = createDynamicShortcuts(emptyResolver(), mockShortcutManager); sut.updatePinned(); Loading Loading @@ -187,8 +183,20 @@ public class DynamicShortcutsTests extends AndroidTestCase { assertThat(arg.get(2), isShortcutForContact(3l, "starred_2", "Starred Two")); } public void test_handleFlagDisabled_stopsJob() { final ShortcutManager mockShortcutManager = mock(ShortcutManager.class); final JobScheduler mockJobScheduler = mock(JobScheduler.class); final DynamicShortcuts sut = createDynamicShortcuts(emptyResolver(), mockShortcutManager, mockJobScheduler); sut.handleFlagDisabled(); verify(mockJobScheduler).cancel(eq(ContactsJobService.DYNAMIC_SHORTCUTS_JOB_ID)); } public void test_scheduleUpdateJob_schedulesJob() { final DynamicShortcuts sut = createDynamicShortcuts(); final DynamicShortcuts sut = new DynamicShortcuts(getContext()); sut.scheduleUpdateJob(); assertThat(DynamicShortcuts.isJobScheduled(getContext()), Matchers.is(true)); } Loading Loading @@ -266,10 +274,16 @@ public class DynamicShortcutsTests extends AndroidTestCase { return createDynamicShortcuts(emptyResolver(), mock(ShortcutManager.class)); } private DynamicShortcuts createDynamicShortcuts(ContentResolver resolver, ShortcutManager shortcutManager) { return createDynamicShortcuts(resolver, shortcutManager, mock(JobScheduler.class)); } private DynamicShortcuts createDynamicShortcuts(ContentResolver resolver, ShortcutManager shortcutManager, JobScheduler jobScheduler) { final DynamicShortcuts result = new DynamicShortcuts(getContext(), resolver, shortcutManager); shortcutManager, jobScheduler); // Use very long label limits to make checking shortcuts easier to understand result.setShortLabelMaxLength(100); result.setLongLabelMaxLength(100); Loading Loading
src/com/android/contacts/DynamicShortcuts.java +41 −10 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; import android.database.Cursor; Loading Loading @@ -56,8 +55,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import static com.android.contacts.common.list.ShortcutIntentBuilder.INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION; /** * This class creates and updates the dynamic shortcuts displayed on the Nexus launcher for the * Contacts app. Loading Loading @@ -95,17 +92,21 @@ public class DynamicShortcuts { private int mLongLabelMaxLength = LONG_LABEL_MAX_LENGTH; private final int mContentChangeMinUpdateDelay; private final int mContentChangeMaxUpdateDelay; private final JobScheduler mJobScheduler; public DynamicShortcuts(Context context) { this(context, context.getContentResolver(), (ShortcutManager) context.getSystemService(Context.SHORTCUT_SERVICE)); context.getSystemService(Context.SHORTCUT_SERVICE), (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE)); } @VisibleForTesting public DynamicShortcuts(Context context, ContentResolver contentResolver, ShortcutManager shortcutManager) { ShortcutManager shortcutManager, JobScheduler jobScheduler) { mContext = context; mContentResolver = contentResolver; mShortcutManager = shortcutManager; mJobScheduler = jobScheduler; mContentChangeMinUpdateDelay = Flags.getInstance(mContext) .getInteger(Experiments.DYNAMIC_MIN_CONTENT_CHANGE_UPDATE_DELAY_MILLIS); mContentChangeMaxUpdateDelay = Flags.getInstance(mContext) Loading @@ -124,7 +125,11 @@ public class DynamicShortcuts { @VisibleForTesting void refresh() { mShortcutManager.setDynamicShortcuts(getStrequentShortcuts()); final List<ShortcutInfo> shortcuts = getStrequentShortcuts(); mShortcutManager.setDynamicShortcuts(shortcuts); if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "set dynamic shortcuts " + shortcuts); } updatePinned(); } Loading Loading @@ -154,6 +159,12 @@ public class DynamicShortcuts { } } if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "updating " + updates); Log.d(TAG, "enabling " + enable); Log.d(TAG, "disabling " + removedIds); } mShortcutManager.updateShortcuts(updates); mShortcutManager.enableShortcuts(enable); mShortcutManager.disableShortcuts(removedIds, Loading Loading @@ -332,7 +343,8 @@ public class DynamicShortcuts { return result; } private void handleFlagDisabled() { @VisibleForTesting void handleFlagDisabled() { mShortcutManager.removeAllDynamicShortcuts(); final List<ShortcutInfo> pinned = mShortcutManager.getPinnedShortcuts(); Loading @@ -342,6 +354,11 @@ public class DynamicShortcuts { } mShortcutManager.disableShortcuts(ids, mContext .getString(R.string.dynamic_shortcut_disabled_message)); if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "DynamicShortcuts have been removed."); } mJobScheduler.cancel(ContactsJobService.DYNAMIC_SHORTCUTS_JOB_ID); } @VisibleForTesting Loading @@ -356,12 +373,23 @@ public class DynamicShortcuts { JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)) .setTriggerContentUpdateDelay(mContentChangeMinUpdateDelay) .setTriggerContentMaxDelay(mContentChangeMaxUpdateDelay).build(); final JobScheduler scheduler = (JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE); scheduler.schedule(job); mJobScheduler.schedule(job); } public synchronized static void initialize(Context context) { if (Log.isLoggable(TAG, Log.DEBUG)) { final Flags flags = Flags.getInstance(context); Log.d(TAG, "DyanmicShortcuts.initialize\nVERSION >= N_MR1? " + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) + "\n" + Experiments.DYNAMIC_SHORTCUTS + " enabled? " + flags.getBoolean(Experiments.DYNAMIC_SHORTCUTS) + "\nisJobScheduled? " + isJobScheduled(context) + "\nminDelay=" + flags.getInteger(Experiments.DYNAMIC_MIN_CONTENT_CHANGE_UPDATE_DELAY_MILLIS) + "\nmaxDelay=" + flags.getInteger(Experiments.DYNAMIC_MAX_CONTENT_CHANGE_UPDATE_DELAY_MILLIS)); } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) return; final DynamicShortcuts shortcuts = new DynamicShortcuts(context); Loading Loading @@ -413,6 +441,9 @@ public class DynamicShortcuts { @Override protected void onPostExecute(Void aVoid) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "ShorcutUpdateTask.onPostExecute"); } // The shortcuts may have changed so update the job so that we are observing the // correct Uris mDynamicShortcuts.scheduleUpdateJob(); Loading
tests/src/com/android/contacts/DynamicShortcutsTests.java +22 −8 Original line number Diff line number Diff line Loading @@ -52,14 +52,11 @@ import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; @TargetApi(Build.VERSION_CODES.N_MR1) @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N_MR1) // TODO: need to switch to android.support.test.runner.AndroidJUnitRunner for the @SdkSuppress // annotation to be respected. So for now we suppress this test to keep it from failing when run // by the build system. @Suppress @SmallTest public class DynamicShortcutsTests extends AndroidTestCase { Loading Loading @@ -120,8 +117,7 @@ public class DynamicShortcutsTests extends AndroidTestCase { when(mockShortcutManager.getPinnedShortcuts()).thenReturn( Collections.singletonList(shortcutFor(1l, "key1", "name1"))); final DynamicShortcuts sut = new DynamicShortcuts(getContext(), emptyResolver(), mockShortcutManager); final DynamicShortcuts sut = createDynamicShortcuts(emptyResolver(), mockShortcutManager); sut.updatePinned(); Loading Loading @@ -187,8 +183,20 @@ public class DynamicShortcutsTests extends AndroidTestCase { assertThat(arg.get(2), isShortcutForContact(3l, "starred_2", "Starred Two")); } public void test_handleFlagDisabled_stopsJob() { final ShortcutManager mockShortcutManager = mock(ShortcutManager.class); final JobScheduler mockJobScheduler = mock(JobScheduler.class); final DynamicShortcuts sut = createDynamicShortcuts(emptyResolver(), mockShortcutManager, mockJobScheduler); sut.handleFlagDisabled(); verify(mockJobScheduler).cancel(eq(ContactsJobService.DYNAMIC_SHORTCUTS_JOB_ID)); } public void test_scheduleUpdateJob_schedulesJob() { final DynamicShortcuts sut = createDynamicShortcuts(); final DynamicShortcuts sut = new DynamicShortcuts(getContext()); sut.scheduleUpdateJob(); assertThat(DynamicShortcuts.isJobScheduled(getContext()), Matchers.is(true)); } Loading Loading @@ -266,10 +274,16 @@ public class DynamicShortcutsTests extends AndroidTestCase { return createDynamicShortcuts(emptyResolver(), mock(ShortcutManager.class)); } private DynamicShortcuts createDynamicShortcuts(ContentResolver resolver, ShortcutManager shortcutManager) { return createDynamicShortcuts(resolver, shortcutManager, mock(JobScheduler.class)); } private DynamicShortcuts createDynamicShortcuts(ContentResolver resolver, ShortcutManager shortcutManager, JobScheduler jobScheduler) { final DynamicShortcuts result = new DynamicShortcuts(getContext(), resolver, shortcutManager); shortcutManager, jobScheduler); // Use very long label limits to make checking shortcuts easier to understand result.setShortLabelMaxLength(100); result.setLongLabelMaxLength(100); Loading