sdk: Introduce LineagePreferenceLib
Because of some nested dependency breakage, we can no longer include Android libraries in main SDK lib, therefore we are moving all preference related code to a separate package that Settings/LineageParts will depend on. Change-Id: Iea379a580a08ea13f71e3503aa096ba0ed7e7cef
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod 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 lineageos.preference;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A RemotePreference is a view into preference logic which lives in another
|
||||
* process. The primary use case for this is at the platform level where
|
||||
* many applications may be contributing their preferences into the
|
||||
* Settings app.
|
||||
*
|
||||
* A RemotePreference appears as a PreferenceScreen and redirects to
|
||||
* the real application when clicked. The remote application can
|
||||
* send events back to the preference when data changes and the view
|
||||
* needs to be updated. See RemotePreferenceUpdater for a base class
|
||||
* to use on the application side which implements the listeners and
|
||||
* protocol.
|
||||
*
|
||||
* The interprocess communication is realized using BroadcastReceivers.
|
||||
* When the application wants to update the RemotePreference with
|
||||
* new data, it sends an ACTION_REFRESH_PREFERENCE with a particular
|
||||
* Uri. The RemotePreference listens while attached, and performs
|
||||
* an ordered broadcast with ACTION_UPDATE_PREFERENCE back to
|
||||
* the application, which is then returned to the preference after
|
||||
* being filled with new data.
|
||||
*
|
||||
* The external activity should include the META_REMOTE_RECEIVER
|
||||
* and (optionally) the META_REMOTE_KEY strings in it's metadata.
|
||||
* META_REMOTE_RECEIVER must contain the class name of the
|
||||
* RemotePreferenceUpdater which we should request updates from.
|
||||
* META_REMOTE_KEY must contain the key used by the preference
|
||||
* which should match on both sides.
|
||||
*/
|
||||
public class RemotePreference extends SelfRemovingPreference
|
||||
implements RemotePreferenceManager.OnRemoteUpdateListener {
|
||||
|
||||
private static final String TAG = RemotePreference.class.getSimpleName();
|
||||
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
public static final String ACTION_REFRESH_PREFERENCE =
|
||||
"lineageos.intent.action.REFRESH_PREFERENCE";
|
||||
|
||||
public static final String ACTION_UPDATE_PREFERENCE =
|
||||
"lineageos.intent.action.UPDATE_PREFERENCE";
|
||||
|
||||
public static final String META_REMOTE_RECEIVER =
|
||||
"org.lineageos.settings.summary.receiver";
|
||||
|
||||
public static final String META_REMOTE_KEY =
|
||||
"org.lineageos.settings.summary.key";
|
||||
|
||||
public static final String EXTRA_ENABLED = ":lineage:pref_enabled";
|
||||
public static final String EXTRA_KEY = ":lineage:pref_key";
|
||||
public static final String EXTRA_SUMMARY = ":lineage:pref_summary";
|
||||
|
||||
protected final Context mContext;
|
||||
|
||||
public RemotePreference(Context context, AttributeSet attrs,
|
||||
int defStyle, int defStyleRes) {
|
||||
super(context, attrs, defStyle, defStyleRes);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public RemotePreference(Context context, AttributeSet attrs, int defStyle) {
|
||||
this(context, attrs, defStyle, 0);
|
||||
}
|
||||
|
||||
public RemotePreference(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, ConstraintsHelper.getAttr(context,
|
||||
androidx.preference.R.attr.preferenceStyle,
|
||||
android.R.attr.preferenceStyle));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoteUpdated(Bundle bundle) {
|
||||
if (DEBUG) Log.d(TAG, "onRemoteUpdated: " + bundle.toString());
|
||||
|
||||
if (bundle.containsKey(EXTRA_ENABLED)) {
|
||||
boolean available = bundle.getBoolean(EXTRA_ENABLED, true);
|
||||
if (available != isAvailable()) {
|
||||
setAvailable(available);
|
||||
}
|
||||
}
|
||||
if (isAvailable()) {
|
||||
setSummary(bundle.getString(EXTRA_SUMMARY));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttached() {
|
||||
super.onAttached();
|
||||
if (isAvailable()) {
|
||||
RemotePreferenceManager.get(mContext).attach(getKey(), this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetached() {
|
||||
super.onDetached();
|
||||
RemotePreferenceManager.get(mContext).detach(getKey(), this);
|
||||
}
|
||||
|
||||
protected String getRemoteKey(Bundle metaData) {
|
||||
String remoteKey = metaData.getString(META_REMOTE_KEY);
|
||||
return (remoteKey == null || !remoteKey.equals(getKey())) ? null : remoteKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent getReceiverIntent() {
|
||||
final Intent i = getIntent();
|
||||
if (i == null) {
|
||||
Log.w(TAG, "No target intent specified in preference!");
|
||||
return null;
|
||||
}
|
||||
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(i,
|
||||
PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA,
|
||||
UserHandle.myUserId());
|
||||
|
||||
|
||||
if (results.size() == 0) {
|
||||
Log.w(TAG, "No activity found for: " + Objects.toString(i));
|
||||
}
|
||||
|
||||
for (ResolveInfo resolved : results) {
|
||||
ActivityInfo info = resolved.activityInfo;
|
||||
Log.d(TAG, "ResolveInfo " + Objects.toString(resolved));
|
||||
|
||||
Bundle meta = info.metaData;
|
||||
if (meta == null || !meta.containsKey(META_REMOTE_RECEIVER)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String receiverClass = meta.getString(META_REMOTE_RECEIVER);
|
||||
String receiverPackage = info.packageName;
|
||||
String remoteKey = getRemoteKey(meta);
|
||||
|
||||
if (DEBUG) Log.d(TAG, "getReceiverIntent class=" + receiverClass +
|
||||
" package=" + receiverPackage + " key=" + remoteKey);
|
||||
|
||||
if (remoteKey == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Intent ri = new Intent(ACTION_UPDATE_PREFERENCE);
|
||||
ri.setComponent(new ComponentName(receiverPackage, receiverClass));
|
||||
ri.putExtra(EXTRA_KEY, remoteKey);
|
||||
return ri;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user