blob: a3e95b85eb218759b01025714788de7e45a94cde [file] [log] [blame]
/*
* Copyright (C) 2016 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.am;
import android.content.res.Configuration;
/**
* Contains common logic for classes that have override configurations and are organized in a
* hierarchy.
*/
abstract class ConfigurationContainer<E extends ConfigurationContainer> {
/** Contains override configuration settings applied to this configuration container. */
private Configuration mOverrideConfiguration = new Configuration();
/**
* Contains full configuration applied to this configuration container. Corresponds to full
* parent's config with applied {@link #mOverrideConfiguration}.
*/
private Configuration mFullConfiguration = new Configuration();
/**
* Contains merged override configuration settings from the top of the hierarchy down to this
* particular instance. It is different from {@link #mFullConfiguration} because it starts from
* topmost container's override config instead of global config.
*/
private Configuration mMergedOverrideConfiguration = new Configuration();
/**
* Returns full configuration applied to this configuration container.
* This method should be used for getting settings applied in each particular level of the
* hierarchy.
*/
Configuration getConfiguration() {
return mFullConfiguration;
}
/**
* Notify that parent config changed and we need to update full configuration.
* @see #mFullConfiguration
*/
void onConfigurationChanged(Configuration newParentConfig) {
mFullConfiguration.setTo(newParentConfig);
mFullConfiguration.updateFrom(mOverrideConfiguration);
for (int i = getChildCount() - 1; i >= 0; --i) {
final ConfigurationContainer child = getChildAt(i);
child.onConfigurationChanged(mFullConfiguration);
}
}
/** Returns override configuration applied to this configuration container. */
Configuration getOverrideConfiguration() {
return mOverrideConfiguration;
}
/**
* Update override configuration and recalculate full config.
* @see #mOverrideConfiguration
* @see #mFullConfiguration
*/
void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
mOverrideConfiguration.setTo(overrideConfiguration);
// Update full configuration of this container and all its children.
final ConfigurationContainer parent = getParent();
onConfigurationChanged(parent != null ? parent.getConfiguration() : Configuration.EMPTY);
// Update merged override config of this container and all its children.
onMergedOverrideConfigurationChanged();
}
/**
* Get merged override configuration from the top of the hierarchy down to this particular
* instance. This should be reported to client as override config.
*/
Configuration getMergedOverrideConfiguration() {
return mMergedOverrideConfiguration;
}
/**
* Update merged override configuration based on corresponding parent's config and notify all
* its children. If there is no parent, merged override configuration will set equal to current
* override config.
* @see #mMergedOverrideConfiguration
*/
private void onMergedOverrideConfigurationChanged() {
final ConfigurationContainer parent = getParent();
if (parent != null) {
mMergedOverrideConfiguration.setTo(parent.getMergedOverrideConfiguration());
mMergedOverrideConfiguration.updateFrom(mOverrideConfiguration);
} else {
mMergedOverrideConfiguration.setTo(mOverrideConfiguration);
}
for (int i = getChildCount() - 1; i >= 0; --i) {
final ConfigurationContainer child = getChildAt(i);
child.onMergedOverrideConfigurationChanged();
}
}
/**
* Must be called when new parent for the container was set.
*/
void onParentChanged() {
final ConfigurationContainer parent = getParent();
// Removing parent usually means that we've detached this entity to destroy it or to attach
// to another parent. In both cases we don't need to update the configuration now.
if (parent != null) {
// Update full configuration of this container and all its children.
onConfigurationChanged(parent.mFullConfiguration);
// Update merged override configuration of this container and all its children.
onMergedOverrideConfigurationChanged();
}
}
abstract protected int getChildCount();
abstract protected E getChildAt(int index);
abstract protected ConfigurationContainer getParent();
}