blob: 096e94348429ed51587f9cb10aad09a9ddc9d2b9 [file] [log] [blame]
/*
* 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.keyguard.clock;
import android.annotation.Nullable;
import android.content.ContentResolver;
import android.provider.Settings;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Wrapper around Settings used for testing.
*/
public class SettingsWrapper {
private static final String TAG = "ClockFaceSettings";
private static final String CUSTOM_CLOCK_FACE = Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE;
private static final String DOCKED_CLOCK_FACE = Settings.Secure.DOCKED_CLOCK_FACE;
private static final String CLOCK_FIELD = "clock";
private final ContentResolver mContentResolver;
private final Migration mMigration;
SettingsWrapper(ContentResolver contentResolver) {
this(contentResolver, new Migrator(contentResolver));
}
@VisibleForTesting
SettingsWrapper(ContentResolver contentResolver, Migration migration) {
mContentResolver = contentResolver;
mMigration = migration;
}
/**
* Gets the value stored in settings for the custom clock face.
*
* @param userId ID of the user.
*/
String getLockScreenCustomClockFace(int userId) {
return decode(
Settings.Secure.getStringForUser(mContentResolver, CUSTOM_CLOCK_FACE, userId),
userId);
}
/**
* Gets the value stored in settings for the clock face to use when docked.
*
* @param userId ID of the user.
*/
String getDockedClockFace(int userId) {
return Settings.Secure.getStringForUser(mContentResolver, DOCKED_CLOCK_FACE, userId);
}
/**
* Decodes the string stored in settings, which should be formatted as JSON.
* @param value String stored in settings. If value is not JSON, then the settings is
* overwritten with JSON containing the prior value.
* @return ID of the clock face to show on AOD and lock screen. If value is not JSON, the value
* is returned.
*/
@VisibleForTesting
String decode(@Nullable String value, int userId) {
if (value == null) {
return value;
}
JSONObject json;
try {
json = new JSONObject(value);
} catch (JSONException ex) {
Log.e(TAG, "Settings value is not valid JSON", ex);
// The settings value isn't JSON since it didn't parse so migrate the value to JSON.
// TODO(b/135674383): Remove this migration path in the following release.
mMigration.migrate(value, userId);
return value;
}
try {
return json.getString(CLOCK_FIELD);
} catch (JSONException ex) {
Log.e(TAG, "JSON object does not contain clock field.", ex);
return null;
}
}
interface Migration {
void migrate(String value, int userId);
}
/**
* Implementation of {@link Migration} that writes valid JSON back to Settings.
*/
private static final class Migrator implements Migration {
private final ContentResolver mContentResolver;
Migrator(ContentResolver contentResolver) {
mContentResolver = contentResolver;
}
/**
* Migrate settings values that don't parse by converting to JSON format.
*
* Values in settings must be JSON to be backed up and restored. To help users maintain
* their current settings, convert existing values into the JSON format.
*
* TODO(b/135674383): Remove this migration code in the following release.
*/
@Override
public void migrate(String value, int userId) {
try {
JSONObject json = new JSONObject();
json.put(CLOCK_FIELD, value);
Settings.Secure.putStringForUser(mContentResolver, CUSTOM_CLOCK_FACE,
json.toString(),
userId);
} catch (JSONException ex) {
Log.e(TAG, "Failed migrating settings value to JSON format", ex);
}
}
}
}