Permalink
Commits on Nov 12, 2018
  1. Ensure that Source Settings button appears

    ianhanniballake committed Nov 12, 2018
    Use the PackageManager.GET_META_DATA flag to ensure that we have the metadata necessary to determine if the selected MuzeiArtProvider has a settings screen.
Commits on Nov 11, 2018
  1. Merge pull request #592 from ianhanniballake/set_multiple

    ianhanniballake committed Nov 11, 2018
    Provide an setArtwork API that takes multiple Artwork
  2. Provide an setArtwork API that takes multiple Artwork

    ianhanniballake committed Nov 11, 2018
    Rather than having MuzeiArtProvider developers bulk insert artwork and then have to manually diff their MuzeiArtProvider to delete no longer valid artwork, provide a setArtwork method that takes multiple artwork.
  3. Merge pull request #591 from ianhanniballake/bulkInsert

    ianhanniballake committed Nov 11, 2018
    Provide an addArtwork API that takes multiple Artwork
  4. Provide an addArtwork API that takes multiple Artwork

    ianhanniballake committed Nov 11, 2018
    Rather than inserting each Artwork one at a time, allow MuzeiArtProvider developers to bulk insert Artwork.
  5. Merge pull request #590 from ianhanniballake/provider_client

    ianhanniballake committed Nov 11, 2018
    Move static methods in ProviderContract.Artwork to ProviderClient
  6. Move static methods in ProviderContract.Artwork to ProviderClient

    ianhanniballake committed Nov 11, 2018
    Instead of keeping a duplicate of each static method in ProviderClient (one using a Class and another using an authority String), create a new interface called ProviderClient that encapsulates all of the static methods.
    
    MuzeiArtProvider itself implements ProviderClient, while instances can be created from new static methods on ProviderContract.
Commits on Nov 9, 2018
  1. Use CoroutineWorker for suspending doWork methods

    ianhanniballake committed Nov 9, 2018
    Rather than runBlocking() on a CoroutineContext, use CoroutineWorker to unblock WorkManager's thread.
  2. Upgrade to WorkManager 1.0.0-alpha11

    ianhanniballake committed Nov 9, 2018
    Use enqueueUniqueWork instead of beingUniqueWork+enqueue()
Commits on Nov 5, 2018
Commits on Nov 3, 2018
Commits on Oct 31, 2018
  1. Skip disabling DataLayerArtProvider from CapabilityListenerService

    ianhanniballake committed Oct 31, 2018
    The list of nodes can be empty not only when Muzei is uninstalled, but also when the watch loses connectivity to the phone - even in simple cases like the watch going into airplane mode.
    
    We shouldn't disable the From Phone source in those cases. This has the negative side effect that after actually uninstalling Muzei on their phone, they'll still have the From Phone source selected, but that is preferable to the current state of the world and easily fixed by users.
Commits on Oct 30, 2018
  1. Avoid overloading ProviderChangedWorker with many changes

    ianhanniballake committed Oct 30, 2018
    Change ProviderChangedWorker.enqueueChanged() to use unique work with REPLACE to ensure there's only at most one pending Worker waiting to execute. Add an initial delay to avoid cases where many of these Workers stack up due to their immediate launch.
    
    Changes handleProviderChange() to be more cautious on what enqueues it should be calling, avoiding cases where we could call both enqueuePeriodic() and enqueueNext(), which can lead to multiple calls to ProviderChangedWorker (as enqueuePeriodic() can cause work to immediately run).
  2. Fix infinite loop on BitmapTransformation.equals()

    ianhanniballake committed Oct 30, 2018
    Fatal Exception: java.lang.StackOverflowError: stack size 8MB
           at kotlin.jvm.internal.Intrinsics.areEqual(Intrinsics.java:153)
           at com.google.android.apps.muzei.render.MuzeiRendererFragment$simpleDemoModeTransformation$1.equals(MuzeiRendererFragment.kt:85)
           at kotlin.jvm.internal.Intrinsics.areEqual(Intrinsics.java:153)
           at com.google.android.apps.muzei.render.MuzeiRendererFragment$simpleDemoModeTransformation$1.equals(MuzeiRendererFragment.kt:85)
           at kotlin.jvm.internal.Intrinsics.areEqual(Intrinsics.java:153)
           at com.google.android.apps.muzei.render.MuzeiRendererFragment$simpleDemoModeTransformation$1.equals(MuzeiRendererFragment.kt:85)
           at kotlin.jvm.internal.Intrinsics.areEqual(Intrinsics.java:153)
           at com.google.android.apps.muzei.render.MuzeiRendererFragment$simpleDemoModeTransformation$1.equals(MuzeiRendererFragment.kt:85)
           at kotlin.jvm.internal.Intrinsics.areEqual(Intrinsics.java:153)
           at com.google.android.apps.muzei.render.MuzeiRendererFragment$simpleDemoModeTransformation$1.equals(MuzeiRendererFragment.kt:85)
           at kotlin.jvm.internal.Intrinsics.areEqual(Intrinsics.java:153)
           at com.google.android.apps.muzei.render.MuzeiRendererFragment$simpleDemoModeTransformation$1.equals(MuzeiRendererFragment.kt:85)
           at kotlin.jvm.internal.Intrinsics.areEqual(Intrinsics.java:153)
           at com.google.android.apps.muzei.render.MuzeiRendererFragment$simpleDemoModeTransformation$1.equals(MuzeiRendererFragment.kt:85)
           at kotlin.jvm.internal.Intrinsics.areEqual(Intrinsics.java:153)
           at com.google.android.apps.muzei.render.MuzeiRendererFragment$simpleDemoModeTransformation$1.equals(MuzeiRendererFragment.kt:85)
           at kotlin.jvm.internal.Intrinsics.areEqual(Intrinsics.java:153)
           at com.google.android.apps.muzei.render.MuzeiRendererFragment$simpleDemoModeTransformation$1.equals(MuzeiRendererFragment.kt:85)
           at kotlin.jvm.internal.Intrinsics.areEqual(Intrinsics.java:153)
           at com.google.android.apps.muzei.render.MuzeiRendererFragment$simpleDemoModeTransformation$1.equals(MuzeiRendererFragment.kt:85)
           at java.util.AbstractList.equals(AbstractList.java:494)
           at com.bumptech.glide.load.MultiTransformation.equals(MultiTransformation.java:56)
           at com.bumptech.glide.load.resource.bitmap.DrawableTransformation.equals(DrawableTransformation.java:85)
           at android.support.v4.util.SimpleArrayMap.equals(SimpleArrayMap.java:612)
           at com.bumptech.glide.load.engine.EngineKey.equals(EngineKey.java:54)
           at java.util.HashMap.remove(HashMap.java:621)
           at com.bumptech.glide.util.LruCache.remove(LruCache.java:153)
           at com.bumptech.glide.load.engine.cache.LruResourceCache.remove(LruResourceCache.java:13)
           at com.bumptech.glide.load.engine.Engine.getEngineResourceFromCache(Engine.java:270)
           at com.bumptech.glide.load.engine.Engine.loadFromCache(Engine.java:261)
           at com.bumptech.glide.load.engine.Engine.load(Engine.java:183)
           at com.bumptech.glide.request.SingleRequest.onSizeReady(SingleRequest.java:432)
           at com.bumptech.glide.request.SingleRequest.begin(SingleRequest.java:255)
           at com.bumptech.glide.manager.RequestTracker.resumeRequests(RequestTracker.java:128)
           at com.bumptech.glide.RequestManager.resumeRequests(RequestManager.java:256)
           at com.bumptech.glide.RequestManager.onStart(RequestManager.java:281)
           at com.bumptech.glide.manager.ActivityFragmentLifecycle.onStart(ActivityFragmentLifecycle.java:51)
           at com.bumptech.glide.manager.SupportRequestManagerFragment.onStart(SupportRequestManagerFragment.java:182)
           at android.support.v4.app.Fragment.performStart(Fragment.java:2477)
           at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1494)
           at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
           at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
           at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3269)
           at android.support.v4.app.FragmentManagerImpl.dispatchStart(FragmentManager.java:3235)
           at android.support.v4.app.Fragment.performStart(Fragment.java:2483)
           at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1494)
           at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
           at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
           at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3269)
           at android.support.v4.app.FragmentManagerImpl.dispatchStart(FragmentManager.java:3235)
           at android.support.v4.app.Fragment.performStart(Fragment.java:2483)
           at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1494)
           at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
           at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
           at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3269)
           at android.support.v4.app.FragmentManagerImpl.dispatchStart(FragmentManager.java:3235)
           at android.support.v4.app.FragmentController.dispatchStart(FragmentController.java:212)
           at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:628)
           at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
           at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1260)
           at android.app.Activity.performStart(Activity.java:6261)
           at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2389)
           at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2490)
           at android.app.ActivityThread.-wrap11(ActivityThread.java)
           at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1354)
           at android.os.Handler.dispatchMessage(Handler.java:102)
           at android.os.Looper.loop(Looper.java:148)
           at android.app.ActivityThread.main(ActivityThread.java:5443)
           at java.lang.reflect.Method.invoke(Method.java)
           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
  3. Catch all Exceptions from DirectBootCache

    ianhanniballake committed Oct 30, 2018
    Fatal Exception: java.lang.SecurityException: Artwork was marked as invalid
           at com.google.android.apps.muzei.api.provider.MuzeiArtProvider.openFile(MuzeiArtProvider.java:882)
           at android.content.ContentProvider.openAssetFile(ContentProvider.java:1556)
           at android.content.ContentProvider.openTypedAssetFile(ContentProvider.java:1736)
           at android.content.ContentProvider.openTypedAssetFile(ContentProvider.java:1802)
           at android.content.ContentProvider$Transport.openTypedAssetFile(ContentProvider.java:428)
           at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1412)
           at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1249)
           at android.content.ContentResolver.openFileDescriptor(ContentResolver.java:1102)
           at android.content.ContentResolver.openFileDescriptor(ContentResolver.java:1056)
           at com.google.android.apps.muzei.provider.MuzeiProvider.openFileArtwork(MuzeiProvider.kt:263)
           at com.google.android.apps.muzei.provider.MuzeiProvider.openFile(MuzeiProvider.kt:240)
           at android.content.ContentProvider.openAssetFile(ContentProvider.java:1556)
           at android.content.ContentProvider.openTypedAssetFile(ContentProvider.java:1736)
           at android.content.ContentProvider.openTypedAssetFile(ContentProvider.java:1802)
           at android.content.ContentProvider$Transport.openTypedAssetFile(ContentProvider.java:428)
           at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1412)
           at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1249)
           at android.content.ContentResolver.openInputStream(ContentResolver.java:969)
           at com.google.android.apps.muzei.provider.DirectBootCache$onArtworkChanged$1.doResume(DirectBootCache.kt:60)
           at kotlin.coroutines.experimental.jvm.internal.CoroutineImpl.resume(CoroutineImpl.kt:42)
           at kotlinx.coroutines.experimental.DispatchedTask$DefaultImpls.run(Dispatched.kt:149)
           at kotlinx.coroutines.experimental.AbstractContinuation.run(AbstractContinuation.kt:19)
           at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1412)
           at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:285)
           at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1152)
           at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1990)
           at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1938)
           at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Commits on Oct 27, 2018
  1. Reduce the priority of providers crashing

    ianhanniballake committed Oct 27, 2018
    Most provider crashes are not something Muzei can do anything about, so we don't need Log.w or Crashlytics logging.
  2. Catch and log exceptions raised by sync workers

    ianhanniballake committed Oct 27, 2018
    Move Crashlytics and other Firebase dependencies to android-client-common, then use Crashlytics to log non-fatal exceptions from providers.
    
    Add better exclude rules to dependencies to avoid media-compat sneaking in.
  3. Fix isArtworkValid for locally stored Gallery images

    ianhanniballake committed Oct 27, 2018
    getCacheFileForUri() should only be used with the metadata column as that's the column that GalleryProvider works off of.
    
    This corrects an issue where local images (i.e., those we don't have persistent permission to view) are always marked as invalid, causing a spiral where they are all deleted, then onLoadRequested fills them back in, only to have them all deleted again.
Commits on Oct 26, 2018
  1. Fix setOnMenuItemClickListener crash after detach

    ianhanniballake committed Oct 26, 2018
    Fatal Exception: java.lang.IllegalStateException: Fragment ChooseProviderFragment{4fe4919} not attached to a context.
           at android.support.v4.app.Fragment.requireContext(Fragment.java:696)
           at com.google.android.apps.muzei.ChooseProviderFragment$onViewCreated$1.onMenuItemClick(ChooseProviderFragment.kt:135)
           at android.support.v7.widget.Toolbar$1.onMenuItemClick(Toolbar.java:204)
           at android.support.v7.widget.ActionMenuView$MenuBuilderCallback.onMenuItemSelected(ActionMenuView.java:781)
           at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:840)
           at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:158)
           at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:991)
           at android.support.v7.view.menu.MenuPopup.onItemClick(MenuPopup.java:128)
           at android.widget.AdapterView.performItemClick(AdapterView.java:345)
           at android.widget.AbsListView.performItemClick(AbsListView.java:1547)
           at android.widget.AbsListView$PerformClick.run(AbsListView.java:3821)
           at android.widget.AbsListView$3.run(AbsListView.java:5841)
           at android.os.Handler.handleCallback(Handler.java:739)
           at android.os.Handler.dispatchMessage(Handler.java:95)
           at android.os.Looper.loop(Looper.java:158)
           at android.app.ActivityThread.main(ActivityThread.java:7224)
           at java.lang.reflect.Method.invoke(Method.java)
           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
  2. Replace Picasso with Glide to fix image rotation issues

    ianhanniballake committed Oct 26, 2018
    Picasso doesn't read rotation from ExifInterface for content URIs, but Glide does.
    
    Fixes rotation on the Sources screen, Browse screen, and the 'My Photos' settings screen.
    
    Due to Glide's increased size over Picasso, enabled multidex on the main project. As we run ProGuard on release builds, the release APK ends up still being just one dex file, so this really only impacts dev builds.
  3. Split Wear main app into a separate taskAffinity

    ianhanniballake committed Oct 26, 2018
    Avoid cases where the user sees the watch face settings or another settings screen when they open the main app.
Commits on Oct 25, 2018
  1. Never delete a ChosenPhoto from openFile(Artwork)

    ianhanniballake committed Oct 25, 2018
    Deleting individual photos from GalleryArtProvider is fine, but ChosenPhotos should only be cleaned up by GalleryScanWorker to avoid accidentally deleting something that the user still has access to.