Loading res/values/override.xml +2 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ <resources> <string name="themes_stub_package" translatable="false"/> <string name="clocks_stub_package" translatable="false"/> <!-- Authority of a provider in System UI that will provide preview info for available clockfaces. --> <string name="clocks_provider_authority" translatable="false">com.android.keyguard.clock</string> <!--Name of metadata in the main launcher Activity which values contains the authority corresponding to a ContentProvider in launcher to provide available grids and Loading src/com/android/customization/model/clock/Clockface.java +14 −10 Original line number Diff line number Diff line Loading @@ -15,7 +15,8 @@ */ package com.android.customization.model.clock; import android.graphics.drawable.Drawable; import android.content.Context; import android.provider.Settings.Secure; import android.text.TextUtils; import android.view.View; import android.widget.ImageView; Loading @@ -23,15 +24,16 @@ import android.widget.ImageView; import com.android.customization.model.CustomizationManager; import com.android.customization.model.CustomizationOption; import com.android.wallpaper.R; import com.android.wallpaper.asset.Asset; public class Clockface implements CustomizationOption<Clockface> { private final String mTitle; private final String mId; private final Drawable mPreview; private final Drawable mThumbnail; private final Asset mPreview; private final Asset mThumbnail; private Clockface(String title, String id, Drawable preview, Drawable thumbnail) { private Clockface(String title, String id, Asset preview, Asset thumbnail) { mTitle = title; mId = id; mPreview = preview; Loading @@ -45,7 +47,9 @@ public class Clockface implements CustomizationOption<Clockface> { @Override public void bindThumbnailTile(View view) { ((ImageView) view.findViewById(R.id.clock_option_thumbnail)).setImageDrawable(mThumbnail); ImageView thumbView = view.findViewById(R.id.clock_option_thumbnail); mThumbnail.loadDrawableWithTransition(thumbView.getContext(), thumbView, 50, null, thumbView.getResources().getColor(android.R.color.transparent, null)); } @Override Loading @@ -61,7 +65,7 @@ public class Clockface implements CustomizationOption<Clockface> { return R.layout.clock_option; } public Drawable getPreviewDrawable() { public Asset getPreviewAsset() { return mPreview; } Loading @@ -72,8 +76,8 @@ public class Clockface implements CustomizationOption<Clockface> { public static class Builder { private String mTitle; private String mId; private Drawable mPreview; private Drawable mThumbnail; private Asset mPreview; private Asset mThumbnail; public Clockface build() { return new Clockface(mTitle, mId, mPreview, mThumbnail); Loading @@ -89,12 +93,12 @@ public class Clockface implements CustomizationOption<Clockface> { return this; } public Builder setPreview(Drawable preview) { public Builder setPreview(Asset preview) { mPreview = preview; return this; } public Builder setThumbnail(Drawable thumbnail) { public Builder setThumbnail(Asset thumbnail) { mThumbnail = thumbnail; return this; } Loading src/com/android/customization/model/clock/ContentProviderClockProvider.java 0 → 100644 +130 −0 Original line number Diff line number Diff line package com.android.customization.model.clock; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; import android.text.TextUtils; import com.android.customization.model.CustomizationManager.OptionsFetchedListener; import com.android.customization.model.clock.Clockface.Builder; import com.android.wallpaper.R; import com.android.wallpaper.asset.ContentUriAsset; import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; import java.util.ArrayList; import java.util.List; public class ContentProviderClockProvider implements ClockProvider { private final Context mContext; private final ProviderInfo mProviderInfo; private List<Clockface> mClocks; public ContentProviderClockProvider(Context context) { mContext = context; String providerAuthority = mContext.getString(R.string.clocks_provider_authority); // TODO: check permissions if needed mProviderInfo = TextUtils.isEmpty(providerAuthority) ? null : mContext.getPackageManager().resolveContentProvider(providerAuthority, PackageManager.MATCH_SYSTEM_ONLY); } @Override public boolean isAvailable() { return mProviderInfo != null; } @Override public void fetch(OptionsFetchedListener<Clockface> callback, boolean reload) { if (!isAvailable()) { if (callback != null) { callback.onOptionsLoaded(null); } return; } if (mClocks != null && !reload) { if (callback != null) { callback.onOptionsLoaded(mClocks); } return; } new ClocksFetchTask(mContext, mProviderInfo, options -> { mClocks = options; if (callback != null) { callback.onOptionsLoaded(mClocks); } }).execute(); } private static class ClocksFetchTask extends AsyncTask<Void, Void, List<Clockface>> { private static final String LIST_OPTIONS = "list_options"; private static final String COL_NAME = "name"; private static final String COL_TITLE = "title"; private static final String COL_ID = "id"; private static final String COL_THUMBNAIL = "thumbnail"; private static final String COL_PREVIEW = "preview"; private final OptionsFetchedListener<Clockface> mCallback; private Context mContext; private final ProviderInfo mProviderInfo; public ClocksFetchTask(Context context, ProviderInfo providerInfo, OptionsFetchedListener<Clockface> callback) { super(); mContext = context; mProviderInfo = providerInfo; mCallback = callback; } @Override protected List<Clockface> doInBackground(Void... voids) { Uri optionsUri = new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(mProviderInfo.authority) .appendPath(LIST_OPTIONS) .build(); ContentResolver resolver = mContext.getContentResolver(); List<Clockface> clockfaces = new ArrayList<>(); try (Cursor c = resolver.query(optionsUri, null, null, null, null)) { while(c.moveToNext()) { String id = c.getString(c.getColumnIndex(COL_ID)); String title = c.getString(c.getColumnIndex(COL_TITLE)); String thumbnailUri = c.getString(c.getColumnIndex(COL_THUMBNAIL)); String previewUri = c.getString(c.getColumnIndex(COL_PREVIEW)); Uri thumbnail = Uri.parse(thumbnailUri); Uri preview = Uri.parse(previewUri); Clockface.Builder builder = new Builder(); builder.setId(id).setTitle(title) .setThumbnail(new ContentUriAsset(mContext, thumbnail, RequestOptions.fitCenterTransform())) .setPreview(new ContentUriAsset(mContext, preview, RequestOptions.fitCenterTransform())); clockfaces.add(builder.build()); } Glide.get(mContext).clearDiskCache(); } catch (Exception e) { clockfaces = null; } finally { mContext = null; } return clockfaces; } @Override protected void onPostExecute(List<Clockface> clockfaces) { super.onPostExecute(clockfaces); mCallback.onOptionsLoaded(clockfaces); } } } src/com/android/customization/model/clock/ResourcesApkClockProvider.javadeleted 100644 → 0 +0 −76 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.customization.model.clock; import android.content.Context; import android.content.res.Resources.NotFoundException; import android.util.Log; import com.android.customization.model.CustomizationManager.OptionsFetchedListener; import com.android.customization.model.ResourcesApkProvider; import com.android.customization.model.clock.Clockface.Builder; import com.android.wallpaper.R; import java.util.ArrayList; import java.util.List; public class ResourcesApkClockProvider extends ResourcesApkProvider implements ClockProvider { private static final String TAG = "ResourcesApkClockProvider"; private static final String CLOCKS_ARRAY = "clocks"; private static final String TITLE_PREFIX = "clock_title_"; private static final String ID_PREFIX = "clock_id_"; private static final String PREVIEW_PREFIX = "clock_preview_"; private static final String THUMBNAIL_PREFIX = "clock_thumbnail_"; private List<Clockface> mClocks; public ResourcesApkClockProvider(Context context){ super(context, context.getString(R.string.clocks_stub_package)); } @Override public void fetch(OptionsFetchedListener<Clockface> callback, boolean reload) { if (mClocks == null || reload) { mClocks = new ArrayList<>(); loadAll(); } if(callback != null) { callback.onOptionsLoaded(mClocks); } } private void loadAll() { String[] clockNames = getItemsFromStub(CLOCKS_ARRAY); for (String clockName : clockNames) { try { Builder builder = new Builder(); builder.setTitle(getItemStringFromStub(TITLE_PREFIX, clockName)) .setId(getItemStringFromStub(ID_PREFIX, clockName)) .setPreview(getItemDrawableFromStub(PREVIEW_PREFIX, clockName)) .setThumbnail(getItemDrawableFromStub(THUMBNAIL_PREFIX, clockName)); mClocks.add(builder.build()); } catch (NotFoundException e) { Log.i(TAG, "Resource not found, skipping clock", e); } } } } src/com/android/customization/picker/CustomizationPickerActivity.java +3 −2 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ import com.android.customization.model.CustomizationManager; import com.android.customization.model.CustomizationOption; import com.android.customization.model.clock.ClockManager; import com.android.customization.model.clock.Clockface; import com.android.customization.model.clock.ResourcesApkClockProvider; import com.android.customization.model.clock.ContentProviderClockProvider; import com.android.customization.model.grid.GridOption; import com.android.customization.model.grid.GridOptionsManager; import com.android.customization.model.grid.LauncherGridOptionsProvider; Loading Loading @@ -134,7 +134,8 @@ public class CustomizationPickerActivity extends FragmentActivity implements Wal mSections.put(R.id.nav_theme, new ThemeSection(R.id.nav_theme, themeManager)); } //Clock ClockManager clockManager = new ClockManager(this, new ResourcesApkClockProvider(this)); //ClockManager clockManager = new ClockManager(this, new ResourcesApkClockProvider(this)); ClockManager clockManager = new ClockManager(this, new ContentProviderClockProvider(this)); if (clockManager.isAvailable()) { mSections.put(R.id.nav_clock, new ClockSection(R.id.nav_clock, clockManager)); } Loading Loading
res/values/override.xml +2 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ <resources> <string name="themes_stub_package" translatable="false"/> <string name="clocks_stub_package" translatable="false"/> <!-- Authority of a provider in System UI that will provide preview info for available clockfaces. --> <string name="clocks_provider_authority" translatable="false">com.android.keyguard.clock</string> <!--Name of metadata in the main launcher Activity which values contains the authority corresponding to a ContentProvider in launcher to provide available grids and Loading
src/com/android/customization/model/clock/Clockface.java +14 −10 Original line number Diff line number Diff line Loading @@ -15,7 +15,8 @@ */ package com.android.customization.model.clock; import android.graphics.drawable.Drawable; import android.content.Context; import android.provider.Settings.Secure; import android.text.TextUtils; import android.view.View; import android.widget.ImageView; Loading @@ -23,15 +24,16 @@ import android.widget.ImageView; import com.android.customization.model.CustomizationManager; import com.android.customization.model.CustomizationOption; import com.android.wallpaper.R; import com.android.wallpaper.asset.Asset; public class Clockface implements CustomizationOption<Clockface> { private final String mTitle; private final String mId; private final Drawable mPreview; private final Drawable mThumbnail; private final Asset mPreview; private final Asset mThumbnail; private Clockface(String title, String id, Drawable preview, Drawable thumbnail) { private Clockface(String title, String id, Asset preview, Asset thumbnail) { mTitle = title; mId = id; mPreview = preview; Loading @@ -45,7 +47,9 @@ public class Clockface implements CustomizationOption<Clockface> { @Override public void bindThumbnailTile(View view) { ((ImageView) view.findViewById(R.id.clock_option_thumbnail)).setImageDrawable(mThumbnail); ImageView thumbView = view.findViewById(R.id.clock_option_thumbnail); mThumbnail.loadDrawableWithTransition(thumbView.getContext(), thumbView, 50, null, thumbView.getResources().getColor(android.R.color.transparent, null)); } @Override Loading @@ -61,7 +65,7 @@ public class Clockface implements CustomizationOption<Clockface> { return R.layout.clock_option; } public Drawable getPreviewDrawable() { public Asset getPreviewAsset() { return mPreview; } Loading @@ -72,8 +76,8 @@ public class Clockface implements CustomizationOption<Clockface> { public static class Builder { private String mTitle; private String mId; private Drawable mPreview; private Drawable mThumbnail; private Asset mPreview; private Asset mThumbnail; public Clockface build() { return new Clockface(mTitle, mId, mPreview, mThumbnail); Loading @@ -89,12 +93,12 @@ public class Clockface implements CustomizationOption<Clockface> { return this; } public Builder setPreview(Drawable preview) { public Builder setPreview(Asset preview) { mPreview = preview; return this; } public Builder setThumbnail(Drawable thumbnail) { public Builder setThumbnail(Asset thumbnail) { mThumbnail = thumbnail; return this; } Loading
src/com/android/customization/model/clock/ContentProviderClockProvider.java 0 → 100644 +130 −0 Original line number Diff line number Diff line package com.android.customization.model.clock; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; import android.text.TextUtils; import com.android.customization.model.CustomizationManager.OptionsFetchedListener; import com.android.customization.model.clock.Clockface.Builder; import com.android.wallpaper.R; import com.android.wallpaper.asset.ContentUriAsset; import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; import java.util.ArrayList; import java.util.List; public class ContentProviderClockProvider implements ClockProvider { private final Context mContext; private final ProviderInfo mProviderInfo; private List<Clockface> mClocks; public ContentProviderClockProvider(Context context) { mContext = context; String providerAuthority = mContext.getString(R.string.clocks_provider_authority); // TODO: check permissions if needed mProviderInfo = TextUtils.isEmpty(providerAuthority) ? null : mContext.getPackageManager().resolveContentProvider(providerAuthority, PackageManager.MATCH_SYSTEM_ONLY); } @Override public boolean isAvailable() { return mProviderInfo != null; } @Override public void fetch(OptionsFetchedListener<Clockface> callback, boolean reload) { if (!isAvailable()) { if (callback != null) { callback.onOptionsLoaded(null); } return; } if (mClocks != null && !reload) { if (callback != null) { callback.onOptionsLoaded(mClocks); } return; } new ClocksFetchTask(mContext, mProviderInfo, options -> { mClocks = options; if (callback != null) { callback.onOptionsLoaded(mClocks); } }).execute(); } private static class ClocksFetchTask extends AsyncTask<Void, Void, List<Clockface>> { private static final String LIST_OPTIONS = "list_options"; private static final String COL_NAME = "name"; private static final String COL_TITLE = "title"; private static final String COL_ID = "id"; private static final String COL_THUMBNAIL = "thumbnail"; private static final String COL_PREVIEW = "preview"; private final OptionsFetchedListener<Clockface> mCallback; private Context mContext; private final ProviderInfo mProviderInfo; public ClocksFetchTask(Context context, ProviderInfo providerInfo, OptionsFetchedListener<Clockface> callback) { super(); mContext = context; mProviderInfo = providerInfo; mCallback = callback; } @Override protected List<Clockface> doInBackground(Void... voids) { Uri optionsUri = new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(mProviderInfo.authority) .appendPath(LIST_OPTIONS) .build(); ContentResolver resolver = mContext.getContentResolver(); List<Clockface> clockfaces = new ArrayList<>(); try (Cursor c = resolver.query(optionsUri, null, null, null, null)) { while(c.moveToNext()) { String id = c.getString(c.getColumnIndex(COL_ID)); String title = c.getString(c.getColumnIndex(COL_TITLE)); String thumbnailUri = c.getString(c.getColumnIndex(COL_THUMBNAIL)); String previewUri = c.getString(c.getColumnIndex(COL_PREVIEW)); Uri thumbnail = Uri.parse(thumbnailUri); Uri preview = Uri.parse(previewUri); Clockface.Builder builder = new Builder(); builder.setId(id).setTitle(title) .setThumbnail(new ContentUriAsset(mContext, thumbnail, RequestOptions.fitCenterTransform())) .setPreview(new ContentUriAsset(mContext, preview, RequestOptions.fitCenterTransform())); clockfaces.add(builder.build()); } Glide.get(mContext).clearDiskCache(); } catch (Exception e) { clockfaces = null; } finally { mContext = null; } return clockfaces; } @Override protected void onPostExecute(List<Clockface> clockfaces) { super.onPostExecute(clockfaces); mCallback.onOptionsLoaded(clockfaces); } } }
src/com/android/customization/model/clock/ResourcesApkClockProvider.javadeleted 100644 → 0 +0 −76 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.customization.model.clock; import android.content.Context; import android.content.res.Resources.NotFoundException; import android.util.Log; import com.android.customization.model.CustomizationManager.OptionsFetchedListener; import com.android.customization.model.ResourcesApkProvider; import com.android.customization.model.clock.Clockface.Builder; import com.android.wallpaper.R; import java.util.ArrayList; import java.util.List; public class ResourcesApkClockProvider extends ResourcesApkProvider implements ClockProvider { private static final String TAG = "ResourcesApkClockProvider"; private static final String CLOCKS_ARRAY = "clocks"; private static final String TITLE_PREFIX = "clock_title_"; private static final String ID_PREFIX = "clock_id_"; private static final String PREVIEW_PREFIX = "clock_preview_"; private static final String THUMBNAIL_PREFIX = "clock_thumbnail_"; private List<Clockface> mClocks; public ResourcesApkClockProvider(Context context){ super(context, context.getString(R.string.clocks_stub_package)); } @Override public void fetch(OptionsFetchedListener<Clockface> callback, boolean reload) { if (mClocks == null || reload) { mClocks = new ArrayList<>(); loadAll(); } if(callback != null) { callback.onOptionsLoaded(mClocks); } } private void loadAll() { String[] clockNames = getItemsFromStub(CLOCKS_ARRAY); for (String clockName : clockNames) { try { Builder builder = new Builder(); builder.setTitle(getItemStringFromStub(TITLE_PREFIX, clockName)) .setId(getItemStringFromStub(ID_PREFIX, clockName)) .setPreview(getItemDrawableFromStub(PREVIEW_PREFIX, clockName)) .setThumbnail(getItemDrawableFromStub(THUMBNAIL_PREFIX, clockName)); mClocks.add(builder.build()); } catch (NotFoundException e) { Log.i(TAG, "Resource not found, skipping clock", e); } } } }
src/com/android/customization/picker/CustomizationPickerActivity.java +3 −2 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ import com.android.customization.model.CustomizationManager; import com.android.customization.model.CustomizationOption; import com.android.customization.model.clock.ClockManager; import com.android.customization.model.clock.Clockface; import com.android.customization.model.clock.ResourcesApkClockProvider; import com.android.customization.model.clock.ContentProviderClockProvider; import com.android.customization.model.grid.GridOption; import com.android.customization.model.grid.GridOptionsManager; import com.android.customization.model.grid.LauncherGridOptionsProvider; Loading Loading @@ -134,7 +134,8 @@ public class CustomizationPickerActivity extends FragmentActivity implements Wal mSections.put(R.id.nav_theme, new ThemeSection(R.id.nav_theme, themeManager)); } //Clock ClockManager clockManager = new ClockManager(this, new ResourcesApkClockProvider(this)); //ClockManager clockManager = new ClockManager(this, new ResourcesApkClockProvider(this)); ClockManager clockManager = new ClockManager(this, new ContentProviderClockProvider(this)); if (clockManager.isAvailable()) { mSections.put(R.id.nav_clock, new ClockSection(R.id.nav_clock, clockManager)); } Loading