Files
packages_apps_Settings/src/com/android/settings/slices/SliceBackgroundWorker.java
Matthew Fritze 1138218abe Create special case mobile data slice
Build the special case mobile data slice for general use,
and for the Internet Connectivity Panel. The Slice controls
the default data subscription, and links to the subscriptions
page.

Bug: 117804089
Fixse: 119411534
Test: robotests & test app.

Change-Id: I31b524a8fe3182a244d940848090e97250632f39
2019-02-08 13:13:28 -08:00

165 lines
5.2 KiB
Java

/*
* Copyright (C) 2018 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.settings.slices;
import android.annotation.MainThread;
import android.annotation.Nullable;
import android.content.Context;
import android.net.Uri;
import android.util.ArrayMap;
import android.util.Log;
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* The Slice background worker is used to make Settings Slices be able to work with data that is
* changing continuously, e.g. available Wi-Fi networks.
*
* The background worker will be started at {@link SettingsSliceProvider#onSlicePinned(Uri)}, be
* stopped at {@link SettingsSliceProvider#onSliceUnpinned(Uri)}, and be closed at {@link
* SettingsSliceProvider#shutdown()}.
*
* {@link SliceBackgroundWorker} caches the results, uses the cache to compare if there is any data
* changed, and then notifies the Slice {@link Uri} to update.
*
* It also stores all instances of all workers to ensure each worker is a Singleton.
*/
public abstract class SliceBackgroundWorker<E> implements Closeable {
private static final String TAG = "SliceBackgroundWorker";
private static final Map<Uri, SliceBackgroundWorker> LIVE_WORKERS = new ArrayMap<>();
private final Context mContext;
private final Uri mUri;
private List<E> mCachedResults;
protected SliceBackgroundWorker(Context context, Uri uri) {
mContext = context;
mUri = uri;
}
protected Uri getUri() {
return mUri;
}
protected Context getContext() {
return mContext;
}
/**
* Returns the singleton instance of the {@link SliceBackgroundWorker} for specified {@link Uri}
* if exists
*/
@Nullable
public static SliceBackgroundWorker getInstance(Uri uri) {
return LIVE_WORKERS.get(uri);
}
/**
* Returns the singleton instance of the {@link SliceBackgroundWorker} for specified {@link
* CustomSliceable}
*/
static SliceBackgroundWorker getInstance(Context context, CustomSliceable sliceable) {
final Uri uri = sliceable.getUri();
SliceBackgroundWorker worker = getInstance(uri);
if (worker == null) {
final Class<? extends SliceBackgroundWorker> workerClass =
sliceable.getBackgroundWorkerClass();
worker = createInstance(context, uri, workerClass);
LIVE_WORKERS.put(uri, worker);
}
return worker;
}
private static SliceBackgroundWorker createInstance(Context context, Uri uri,
Class<? extends SliceBackgroundWorker> clazz) {
Log.d(TAG, "create instance: " + clazz);
try {
return clazz.getConstructor(Context.class, Uri.class).newInstance(context, uri);
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException |
InvocationTargetException e) {
throw new IllegalStateException(
"Invalid slice background worker: " + clazz, e);
}
}
static void shutdown() {
for (SliceBackgroundWorker worker : LIVE_WORKERS.values()) {
try {
worker.close();
} catch (IOException e) {
Log.w(TAG, "Shutting down worker failed", e);
}
}
LIVE_WORKERS.clear();
}
/**
* Called when the Slice is pinned. This is the place to register callbacks or initialize scan
* tasks.
*/
@MainThread
protected abstract void onSlicePinned();
/**
* Called when the Slice is unpinned. This is the place to unregister callbacks or perform any
* final cleanup.
*/
@MainThread
protected abstract void onSliceUnpinned();
/**
* @return a {@link List} of cached results
*/
public final List<E> getResults() {
return mCachedResults == null ? null : new ArrayList<>(mCachedResults);
}
/**
* Update the results when data changes
*/
protected final void updateResults(List<E> results) {
boolean needNotify = false;
if (results == null) {
if (mCachedResults != null) {
needNotify = true;
}
} else {
needNotify = !results.equals(mCachedResults);
}
if (needNotify) {
mCachedResults = results;
notifySliceChange();
}
}
/**
* Notify that data was updated and attempt to sync changes to the Slice.
*/
protected final void notifySliceChange() {
mContext.getContentResolver().notifyChange(mUri, null);
}
}