1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.car.uxr; 18 19 import android.car.drivingstate.CarUxRestrictions; 20 import android.content.Context; 21 import android.util.Log; 22 23 import androidx.annotation.IdRes; 24 import androidx.annotation.NonNull; 25 import androidx.annotation.XmlRes; 26 27 import com.android.car.ui.recyclerview.ContentLimiting; 28 import com.android.car.ui.utils.CarUxRestrictionsUtil; 29 import com.android.car.uxr.CarUxRestrictionsAppConfig.ListConfig; 30 31 /** 32 * A class that can work together with a {@link ContentLimiting} {@link 33 * androidx.recyclerview.widget.RecyclerView.Adapter} object to provide content limiting ability 34 * based on changes to the state of the car, by listening for the latest {@link CarUxRestrictions}. 35 * 36 * <p>This class manages 3 things: 37 * <ul> 38 * <li> Communications with the User Experience Restriction Engine 39 * <li> Looking up app-side overrides for customizing the content-limiting behavior of a given 40 * list of items in a particular screen 41 * <li> Relaying the relevant parts of that information to the registered 42 * adapter at the right time 43 * </ul> 44 * 45 * <p>The app-side overrides are accessed via the {@link CarUxRestrictionsAppConfig} object. 46 * 47 * <p>Because all but one of the dependencies for this class can be instantiated as soon as a 48 * {@link Context} is available, we provide a separate {@link #setAdapter(ContentLimiting)} 49 * API for linking the targeted adapter. That way the registration can happen in a different part of 50 * code, and potentially in a different lifecycle method to provide maximum flexibility. 51 */ 52 public class UxrContentLimiterImpl implements UxrContentLimiter { 53 54 private ContentLimiting mAdapter; 55 private ListConfig mListConfig; 56 57 private final CarUxRestrictionsUtil mCarUxRestrictionsUtil; 58 private final CarUxRestrictionsAppConfig mCarUxRestrictionsAppConfig; 59 private final CarUxRestrictionsUtil.OnUxRestrictionsChangedListener mListener = 60 new Listener(); 61 62 private class Listener implements CarUxRestrictionsUtil.OnUxRestrictionsChangedListener { 63 private static final String TAG = "ContentLimitListener"; 64 65 @Override onRestrictionsChanged(@onNull CarUxRestrictions carUxRestrictions)66 public void onRestrictionsChanged(@NonNull CarUxRestrictions carUxRestrictions) { 67 if (mAdapter == null) { 68 Log.w(TAG, "No adapter registered."); 69 return; 70 } 71 72 int maxItems = getMaxItemsToUse(carUxRestrictions, mAdapter.getConfigurationId()); 73 logD("New limit " + maxItems); 74 mAdapter.setMaxItems(maxItems); 75 } 76 getMaxItemsToUse(CarUxRestrictions carUxRestrictions, @IdRes int id)77 private int getMaxItemsToUse(CarUxRestrictions carUxRestrictions, @IdRes int id) { 78 // Unrelated restrictions are active. Quit early. 79 if ((carUxRestrictions.getActiveRestrictions() 80 & CarUxRestrictions.UX_RESTRICTIONS_LIMIT_CONTENT) 81 == 0) { 82 logD("Lists are unrestricted."); 83 return ContentLimiting.UNLIMITED; 84 } 85 86 if (mListConfig == null || mListConfig.getContentLimit() == null) { 87 logD("No configs found for adapter with the ID: " + id 88 + " Using the default limit"); 89 return carUxRestrictions.getMaxCumulativeContentItems(); 90 } 91 92 logD("Using the provided override."); 93 return mListConfig.getContentLimit(); 94 } 95 logD(String s)96 private void logD(String s) { 97 if (Log.isLoggable(TAG, Log.DEBUG)) { 98 Log.d(TAG, s); 99 } 100 } 101 } 102 103 /** 104 * Constructs a {@link UxrContentLimiterImpl} object given the app context and the XML resource 105 * file to parse the User Experience Restriction override configs from. 106 * 107 * @param context - the app context 108 * @param xmlRes - the UXR override config XML resource 109 */ UxrContentLimiterImpl(Context context, @XmlRes int xmlRes)110 public UxrContentLimiterImpl(Context context, @XmlRes int xmlRes) { 111 mCarUxRestrictionsUtil = CarUxRestrictionsUtil.getInstance(context); 112 mCarUxRestrictionsAppConfig = CarUxRestrictionsAppConfig.getInstance(context, xmlRes); 113 } 114 115 @Override setAdapter(ContentLimiting adapter)116 public void setAdapter(ContentLimiting adapter) { 117 mAdapter = adapter; 118 int key = mAdapter.getConfigurationId(); 119 if (mCarUxRestrictionsAppConfig.getMapping().containsKey(key)) { 120 mListConfig = mCarUxRestrictionsAppConfig.getMapping().get(key); 121 Integer overriddenMessageResId = mListConfig.getScrollingLimitedMessageResId(); 122 if (overriddenMessageResId != null) { 123 mAdapter.setScrollingLimitedMessageResId(overriddenMessageResId); 124 } 125 } 126 } 127 128 /** 129 * Start listening for changes to {@link CarUxRestrictions}. 130 */ start()131 public void start() { 132 mCarUxRestrictionsUtil.register(mListener); 133 } 134 135 /** 136 * Stop listening for changes to {@link CarUxRestrictions}. 137 */ stop()138 public void stop() { 139 mCarUxRestrictionsUtil.unregister(mListener); 140 } 141 } 142