1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.systemui; 16 17 import android.annotation.Nullable; 18 import android.content.Context; 19 import android.content.pm.ActivityInfo; 20 import android.content.res.Configuration; 21 import android.content.res.TypedArray; 22 import android.util.AttributeSet; 23 import android.view.LayoutInflater; 24 import android.view.View; 25 import android.widget.FrameLayout; 26 27 import com.android.systemui.res.R; 28 29 import java.util.ArrayList; 30 import java.util.List; 31 import java.util.Set; 32 33 /** 34 * Custom {@link FrameLayout} that re-inflates when changes to {@link Configuration} happen. 35 * Currently supports changes to density, asset path, and locale. 36 */ 37 public class AutoReinflateContainer extends FrameLayout { 38 39 private static final Set<Integer> SUPPORTED_CHANGES = Set.of( 40 ActivityInfo.CONFIG_LOCALE, 41 ActivityInfo.CONFIG_UI_MODE, 42 ActivityInfo.CONFIG_ASSETS_PATHS, 43 ActivityInfo.CONFIG_DENSITY, 44 ActivityInfo.CONFIG_FONT_SCALE 45 ); 46 47 private final List<InflateListener> mInflateListeners = new ArrayList<>(); 48 private final int mLayout; 49 50 private final Configuration mLastConfig = new Configuration(); 51 AutoReinflateContainer(Context context, @Nullable AttributeSet attrs)52 public AutoReinflateContainer(Context context, @Nullable AttributeSet attrs) { 53 super(context, attrs); 54 55 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoReinflateContainer); 56 if (!a.hasValue(R.styleable.AutoReinflateContainer_android_layout)) { 57 throw new IllegalArgumentException("AutoReinflateContainer must contain a layout"); 58 } 59 mLayout = a.getResourceId(R.styleable.AutoReinflateContainer_android_layout, 0); 60 a.recycle(); 61 inflateLayout(); 62 } 63 64 @Override onConfigurationChanged(Configuration newConfig)65 protected void onConfigurationChanged(Configuration newConfig) { 66 int diff = mLastConfig.updateFrom(newConfig); 67 for (int change: SUPPORTED_CHANGES) { 68 if ((diff & change) != 0) { 69 inflateLayout(); 70 return; 71 } 72 } 73 } 74 inflateLayoutImpl()75 protected void inflateLayoutImpl() { 76 LayoutInflater.from(getContext()).inflate(mLayout, this); 77 } 78 inflateLayout()79 public void inflateLayout() { 80 removeAllViews(); 81 inflateLayoutImpl(); 82 final int N = mInflateListeners.size(); 83 for (int i = 0; i < N; i++) { 84 mInflateListeners.get(i).onInflated(getChildAt(0)); 85 } 86 } 87 addInflateListener(InflateListener listener)88 public void addInflateListener(InflateListener listener) { 89 mInflateListeners.add(listener); 90 listener.onInflated(getChildAt(0)); 91 } 92 93 public interface InflateListener { 94 /** 95 * Called whenever a new view is inflated. 96 */ onInflated(View v)97 void onInflated(View v); 98 } 99 } 100