packages/apps/Settings
Revision | 8469dea09b19da45f9cf791f51c838da46954643 (tree) |
---|---|
Time | 2020-11-27 16:20:20 |
Author | timhypeng <timhypeng@goog...> |
Commiter | tim peng |
Fix java.lang.ArrayIndexOutOfBoundsException in RemoteVolumeGroupController
-Caused by removing and adding preference at the same time
-Make preference operation method synchronized
-Not to update preference by removing and adding. To check session status and update its content to preference
-Post to UI thread to handle the onDeviceListUpdate() callback from framework
Bug: 170049403
Test: make -j50 RunSettingsRoboTests
Merged-In: Ibfc11e1bd99ba2e578b5d9e7dcc9132e372b68dd
Change-Id: Ibfc11e1bd99ba2e578b5d9e7dcc9132e372b68dd
(cherry picked from commit 1268629fda99896bda747a2531c6c3a4480d8cb1)
@@ -102,43 +102,80 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem | ||
102 | 102 | mLocalMediaManager.stopScan(); |
103 | 103 | } |
104 | 104 | |
105 | - private void refreshPreference() { | |
106 | - mPreferenceCategory.removeAll(); | |
105 | + private synchronized void refreshPreference() { | |
107 | 106 | if (!isAvailable()) { |
108 | 107 | mPreferenceCategory.setVisible(false); |
109 | 108 | return; |
110 | 109 | } |
111 | 110 | final CharSequence castVolume = mContext.getText(R.string.remote_media_volume_option_title); |
112 | 111 | mPreferenceCategory.setVisible(true); |
113 | - | |
114 | 112 | for (RoutingSessionInfo info : mRoutingSessionInfos) { |
115 | - if (mPreferenceCategory.findPreference(info.getId()) != null) { | |
116 | - continue; | |
113 | + final CharSequence appName = Utils.getApplicationLabel(mContext, | |
114 | + info.getClientPackageName()); | |
115 | + RemoteVolumeSeekBarPreference seekBarPreference = mPreferenceCategory.findPreference( | |
116 | + info.getId()); | |
117 | + if (seekBarPreference != null) { | |
118 | + // Update slider | |
119 | + if (seekBarPreference.getProgress() != info.getVolume()) { | |
120 | + seekBarPreference.setProgress(info.getVolume()); | |
121 | + } | |
122 | + } else { | |
123 | + // Add slider | |
124 | + seekBarPreference = new RemoteVolumeSeekBarPreference(mContext); | |
125 | + seekBarPreference.setKey(info.getId()); | |
126 | + seekBarPreference.setTitle(castVolume); | |
127 | + seekBarPreference.setMax(info.getVolumeMax()); | |
128 | + seekBarPreference.setProgress(info.getVolume()); | |
129 | + seekBarPreference.setMin(0); | |
130 | + seekBarPreference.setOnPreferenceChangeListener(this); | |
131 | + seekBarPreference.setIcon(R.drawable.ic_volume_remote); | |
132 | + mPreferenceCategory.addPreference(seekBarPreference); | |
117 | 133 | } |
118 | - final CharSequence appName = Utils.getApplicationLabel( | |
119 | - mContext, info.getClientPackageName()); | |
120 | - final CharSequence outputTitle = mContext.getString(R.string.media_output_label_title, | |
121 | - appName); | |
122 | - // Add slider | |
123 | - final RemoteVolumeSeekBarPreference seekBarPreference = | |
124 | - new RemoteVolumeSeekBarPreference(mContext); | |
125 | - seekBarPreference.setKey(info.getId()); | |
126 | - seekBarPreference.setTitle(castVolume); | |
127 | - seekBarPreference.setMax(info.getVolumeMax()); | |
128 | - seekBarPreference.setProgress(info.getVolume()); | |
129 | - seekBarPreference.setMin(0); | |
130 | - seekBarPreference.setOnPreferenceChangeListener(this); | |
131 | - seekBarPreference.setIcon(R.drawable.ic_volume_remote); | |
132 | - mPreferenceCategory.addPreference(seekBarPreference); | |
133 | - // Add output indicator | |
134 | + | |
135 | + Preference switcherPreference = mPreferenceCategory.findPreference( | |
136 | + SWITCHER_PREFIX + info.getId()); | |
134 | 137 | final boolean isMediaOutputDisabled = Utils.isMediaOutputDisabled( |
135 | 138 | mRouterManager, info.getClientPackageName()); |
136 | - final Preference preference = new Preference(mContext); | |
137 | - preference.setKey(SWITCHER_PREFIX + info.getId()); | |
138 | - preference.setTitle(isMediaOutputDisabled ? appName : outputTitle); | |
139 | - preference.setSummary(info.getName()); | |
140 | - preference.setEnabled(!isMediaOutputDisabled); | |
141 | - mPreferenceCategory.addPreference(preference); | |
139 | + final CharSequence outputTitle = mContext.getString(R.string.media_output_label_title, | |
140 | + appName); | |
141 | + if (switcherPreference != null) { | |
142 | + // Update output indicator | |
143 | + switcherPreference.setTitle(isMediaOutputDisabled ? appName : outputTitle); | |
144 | + switcherPreference.setSummary(info.getName()); | |
145 | + switcherPreference.setEnabled(!isMediaOutputDisabled); | |
146 | + } else { | |
147 | + // Add output indicator | |
148 | + switcherPreference = new Preference(mContext); | |
149 | + switcherPreference.setKey(SWITCHER_PREFIX + info.getId()); | |
150 | + switcherPreference.setTitle(isMediaOutputDisabled ? appName : outputTitle); | |
151 | + switcherPreference.setSummary(info.getName()); | |
152 | + switcherPreference.setEnabled(!isMediaOutputDisabled); | |
153 | + mPreferenceCategory.addPreference(switcherPreference); | |
154 | + } | |
155 | + } | |
156 | + | |
157 | + // Check and remove non-active session preference | |
158 | + // There is a pair of preferences for each session. First one is a seekBar preference. | |
159 | + // The second one shows the session information and provide an entry-point to launch output | |
160 | + // switcher. It is unnecessary to go through all preferences. It is fine ignore the second | |
161 | + // preference and only to check the seekBar's key value. | |
162 | + for (int i = 0; i < mPreferenceCategory.getPreferenceCount(); i = i + 2) { | |
163 | + final Preference preference = mPreferenceCategory.getPreference(i); | |
164 | + boolean isActive = false; | |
165 | + for (RoutingSessionInfo info : mRoutingSessionInfos) { | |
166 | + if (TextUtils.equals(preference.getKey(), info.getId())) { | |
167 | + isActive = true; | |
168 | + break; | |
169 | + } | |
170 | + } | |
171 | + if (isActive) { | |
172 | + continue; | |
173 | + } | |
174 | + final Preference switcherPreference = mPreferenceCategory.getPreference(i + 1); | |
175 | + if (switcherPreference != null) { | |
176 | + mPreferenceCategory.removePreference(preference); | |
177 | + mPreferenceCategory.removePreference(switcherPreference); | |
178 | + } | |
142 | 179 | } |
143 | 180 | } |
144 | 181 |
@@ -181,8 +218,10 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem | ||
181 | 218 | // Preference group is not ready. |
182 | 219 | return; |
183 | 220 | } |
184 | - initRemoteMediaSession(); | |
185 | - refreshPreference(); | |
221 | + ThreadUtils.postOnMainThread(() -> { | |
222 | + initRemoteMediaSession(); | |
223 | + refreshPreference(); | |
224 | + }); | |
186 | 225 | } |
187 | 226 | |
188 | 227 | @Override |