blob: 0f1b7119f8cecf13682b011bfeb12e16afd2af1c [file] [log] [blame]
/*
* Copyright (C) 2023 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.server.inputmethod;
import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.LocaleList;
import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
/**
* A set of thread-safe utility methods for the system locals.
*/
final class SystemLocaleWrapper {
/**
* Not intended to be instantiated.
*/
private SystemLocaleWrapper() {
}
private static final AtomicReference<LocaleList> sSystemLocale =
new AtomicReference<>(new LocaleList(Locale.getDefault()));
/**
* Returns {@link LocaleList} for the specified user.
*
* <p>Note: If you call this method twice, it is possible that the second value is different
* from the first value. The caller is responsible for taking care of such cases.</p>
*
* @param userId the ID of the user to query about.
* @return {@link LocaleList} associated with the user.
*/
@AnyThread
@NonNull
static LocaleList get(@UserIdInt int userId) {
// Currently system locale is not per-user.
// TODO(b/30119489): Make this per-user.
return sSystemLocale.get();
}
/**
* Callback for the locale change event. When this gets filed, {@link #get(int)} is already
* updated to return the new value.
*/
interface Callback {
void onLocaleChanged(@NonNull LocaleList prevLocales, @NonNull LocaleList newLocales);
}
/**
* Called when {@link InputMethodManagerService} is about to start.
*
* @param context {@link Context} to be used.
* @param callback {@link Callback} for the locale change events.
*/
@AnyThread
static void onStart(@NonNull Context context, @NonNull Callback callback,
@NonNull Handler handler) {
sSystemLocale.set(context.getResources().getConfiguration().getLocales());
context.registerReceiver(new LocaleChangeListener(context, callback),
new IntentFilter(Intent.ACTION_LOCALE_CHANGED), null, handler);
}
private static final class LocaleChangeListener extends BroadcastReceiver {
@NonNull
private final Context mContext;
@NonNull
private final Callback mCallback;
LocaleChangeListener(@NonNull Context context, @NonNull Callback callback) {
mContext = context;
mCallback = callback;
}
@Override
public void onReceive(Context context, Intent intent) {
if (!Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
return;
}
final LocaleList newLocales = mContext.getResources().getConfiguration().getLocales();
final LocaleList prevLocales = sSystemLocale.getAndSet(newLocales);
if (!Objects.equals(newLocales, prevLocales)) {
mCallback.onLocaleChanged(prevLocales, newLocales);
}
}
}
}