SelectFromListWizardFragment.java revision 44ce0a96ae3043039a231fac44607df20d3186af
165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane/* 265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Copyright (C) 2014 The Android Open Source Project 365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Licensed under the Apache License, Version 2.0 (the "License"); 565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * you may not use this file except in compliance with the License. 665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * You may obtain a copy of the License at 765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * http://www.apache.org/licenses/LICENSE-2.0 965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 1065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Unless required by applicable law or agreed to in writing, software 1165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * distributed under the License is distributed on an "AS IS" BASIS, 1265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * See the License for the specific language governing permissions and 1465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * limitations under the License. 1565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 1665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 1765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lanepackage com.android.tv.settings.connectivity.setup; 1865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 1965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.app.Activity; 2065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.app.Fragment; 2165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.Context; 2221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Fengimport android.content.res.Resources; 2365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.net.wifi.ScanResult; 2465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.net.wifi.WifiManager; 2565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.os.Bundle; 2665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.os.Handler; 2765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.os.Parcel; 2865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.os.Parcelable; 2921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Fengimport android.support.v17.leanback.widget.VerticalGridView; 3021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Fengimport android.support.v7.util.SortedList; 3121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Fengimport android.support.v7.widget.RecyclerView; 3221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Fengimport android.support.v7.widget.util.SortedListAdapterCallback; 3344ce0a96ae3043039a231fac44607df20d3186afPowei Fengimport android.text.TextUtils; 3465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.LayoutInflater; 3565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.View; 3665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.ViewGroup; 37f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Fengimport android.view.ViewTreeObserver.OnPreDrawListener; 3865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.inputmethod.InputMethodManager; 3965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.widget.ImageView; 4065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.widget.TextView; 4165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 426316b89e65828d537da309851529d1295efd5730Tony Mantlerimport com.android.tv.settings.R; 436316b89e65828d537da309851529d1295efd5730Tony Mantlerimport com.android.tv.settings.connectivity.WifiSecurity; 446316b89e65828d537da309851529d1295efd5730Tony Mantlerimport com.android.tv.settings.util.AccessibilityHelper; 456316b89e65828d537da309851529d1295efd5730Tony Mantler 4665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.util.ArrayList; 4765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.util.Comparator; 4821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Fengimport java.util.List; 4921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Fengimport java.util.TreeSet; 5065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 5165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane/** 5265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Displays a UI for selecting a wifi network from a list in the "wizard" style. 5365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 5465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lanepublic class SelectFromListWizardFragment extends Fragment { 5565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 5665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public static class ListItemComparator implements Comparator<ListItem> { 5765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 5865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public int compare(ListItem o1, ListItem o2) { 5921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng int pinnedPos1 = o1.getPinnedPosition(); 6021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng int pinnedPos2 = o2.getPinnedPosition(); 6121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 6221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (pinnedPos1 != PinnedListItem.UNPINNED && pinnedPos2 == PinnedListItem.UNPINNED) { 6321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (pinnedPos1 == PinnedListItem.FIRST) return -1; 6421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (pinnedPos1 == PinnedListItem.LAST) return 1; 6521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 6621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 6721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (pinnedPos1 == PinnedListItem.UNPINNED && pinnedPos2 != PinnedListItem.UNPINNED) { 6821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (pinnedPos2 == PinnedListItem.FIRST) return 1; 6921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (pinnedPos2 == PinnedListItem.LAST) return -1; 7021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 7121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 7221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (pinnedPos1 != PinnedListItem.UNPINNED && pinnedPos2 != PinnedListItem.UNPINNED) { 7321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (pinnedPos1 == pinnedPos2) { 7421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng PinnedListItem po1 = (PinnedListItem) o1; 7521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng PinnedListItem po2 = (PinnedListItem) o2; 7621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return po1.getPinnedPriority() - po2.getPinnedPriority(); 7721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 7821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (pinnedPos1 == PinnedListItem.LAST) return 1; 7921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 8021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return -1; 8121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 8221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 8365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ScanResult o1ScanResult = o1.getScanResult(); 8465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ScanResult o2ScanResult = o2.getScanResult(); 8565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (o1ScanResult == null) { 8665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (o2ScanResult == null) { 8765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return 0; 8865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 8965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return 1; 9065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 9165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 9265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (o2ScanResult == null) { 9365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return -1; 9465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 9565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int levelDiff = o2ScanResult.level - o1ScanResult.level; 9665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (levelDiff != 0) { 9765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return levelDiff; 9865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 9965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return o1ScanResult.SSID.compareTo(o2ScanResult.SSID); 10065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 10165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 10265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 10365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 10465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 10565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public static class ListItem implements Parcelable { 10665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 10765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final String mName; 10865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final int mIconResource; 10965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final int mIconLevel; 11065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final boolean mHasIconLevel; 11165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final ScanResult mScanResult; 11265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 11365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public ListItem(String name, int iconResource) { 11465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mName = name; 11565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mIconResource = iconResource; 11665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mIconLevel = 0; 11765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mHasIconLevel = false; 11865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mScanResult = null; 11965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 12065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 12165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public ListItem(ScanResult scanResult) { 12265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mName = scanResult.SSID; 1237e552863cea67e57b375f3db15e0baf70e22c39eTony Mantler mIconResource = WifiSecurity.NONE == WifiSecurity.getSecurity(scanResult) 1247e552863cea67e57b375f3db15e0baf70e22c39eTony Mantler ? R.drawable.setup_wifi_signal_open 12565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane : R.drawable.setup_wifi_signal_lock; 12665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mIconLevel = WifiManager.calculateSignalLevel(scanResult.level, 4); 12765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mHasIconLevel = true; 12865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mScanResult = scanResult; 12965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 13065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 13165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public String getName() { 13265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return mName; 13365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 13465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 13565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int getIconResource() { 13665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return mIconResource; 13765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 13865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 13965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int getIconLevel() { 14065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return mIconLevel; 14165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 14265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 14365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane boolean hasIconLevel() { 14465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return mHasIconLevel; 14565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 14665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 14765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ScanResult getScanResult() { 14865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return mScanResult; 14965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 15065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 15121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng /** 15221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng * Returns whether this item is pinned to the front/back of a sorted list. Returns 15321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng * PinnedListItem.UNPINNED if the item is not pinned. 15421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng * @return the pinned/unpinned setting for this item. 15521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng */ 15621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public int getPinnedPosition() { 15721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return PinnedListItem.UNPINNED; 15821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 15921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 16065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 16165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public String toString() { 16265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return mName; 16365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 16465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 16565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public static Parcelable.Creator<ListItem> CREATOR = new Parcelable.Creator<ListItem>() { 16665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 16765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 16865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public ListItem createFromParcel(Parcel source) { 1697e552863cea67e57b375f3db15e0baf70e22c39eTony Mantler ScanResult scanResult = source.readParcelable(ScanResult.class.getClassLoader()); 17065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (scanResult == null) { 17165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return new ListItem(source.readString(), source.readInt()); 17265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 17365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return new ListItem(scanResult); 17465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 17565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 17665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 17765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 17865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public ListItem[] newArray(int size) { 17965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return new ListItem[size]; 18065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 18165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane }; 18265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 18365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 18465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public int describeContents() { 18565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return 0; 18665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 18765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 18865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 18965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void writeToParcel(Parcel dest, int flags) { 19065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dest.writeParcelable(mScanResult, flags); 19165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mScanResult == null) { 19265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dest.writeString(mName); 19365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dest.writeInt(mIconResource); 19465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 19565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 19665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 19765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 19865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public boolean equals(Object o) { 19965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (o instanceof ListItem) { 20065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ListItem li = (ListItem) o; 20165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mScanResult == null && li.mScanResult == null) { 20244ce0a96ae3043039a231fac44607df20d3186afPowei Feng return TextUtils.equals(mName, li.mName); 20365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 20444ce0a96ae3043039a231fac44607df20d3186afPowei Feng return (mScanResult != null && li.mScanResult != null 20544ce0a96ae3043039a231fac44607df20d3186afPowei Feng && TextUtils.equals(mName, li.mName) 20644ce0a96ae3043039a231fac44607df20d3186afPowei Feng && WifiSecurity.getSecurity(mScanResult) 20744ce0a96ae3043039a231fac44607df20d3186afPowei Feng == WifiSecurity.getSecurity(li.mScanResult)); 20865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 20965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return false; 21065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 21165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 21265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 21321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public static class PinnedListItem extends ListItem { 21421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public static final int UNPINNED = 0; 21521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public static final int FIRST = 1; 21621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public static final int LAST = 2; 21721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 21821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng private int mPinnedPosition; 21921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng private int mPinnedPriority; 22021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 22121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public PinnedListItem( 22221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng String name, int iconResource, int pinnedPosition, int pinnedPriority) { 22321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng super(name, iconResource); 22421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng mPinnedPosition = pinnedPosition; 22521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng mPinnedPriority = pinnedPriority; 22621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 22721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 22821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng @Override 22921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public int getPinnedPosition() { 23021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return mPinnedPosition; 23121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 23221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 23321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng /** 23421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng * Returns the priority for this item, which is used for ordering the item between pinned 23521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng * items in a sorted list. For example, if two items are pinned to the front of the list 23621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng * (FIRST), the priority value is used to determine their ordering. 23721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng * @return the sorting priority for this item 23821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng */ 23921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public int getPinnedPriority() { 24021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return mPinnedPriority; 24121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 24221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 24321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 24465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public interface Listener { 24565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane void onListSelectionComplete(ListItem listItem); 24665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane void onListFocusChanged(ListItem listItem); 24765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 24865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 24921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng private static interface ActionListener { 25021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public void onClick(ListItem item); 25121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public void onFocus(ListItem item); 25221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 25321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 25421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng private static class ListItemViewHolder extends RecyclerView.ViewHolder { 25521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public ListItemViewHolder(View v) { 25621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng super(v); 25721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 25821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 25921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public void init(ListItem item, View.OnClickListener onClick, 26021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng View.OnFocusChangeListener onFocusChange) { 26121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng TextView title = (TextView) itemView.findViewById(R.id.list_item_text); 26221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng title.setText(item.getName()); 26321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng itemView.setOnClickListener(onClick); 26421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng itemView.setOnFocusChangeListener(onFocusChange); 26521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 26621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng int iconResource = item.getIconResource(); 26721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng ImageView icon = (ImageView) itemView.findViewById(R.id.list_item_icon); 26821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng // Set the icon if there is one. 26921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (iconResource == 0) { 27021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng icon.setVisibility(View.GONE); 27121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return; 27221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 27321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng icon.setVisibility(View.VISIBLE); 27421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng icon.setImageResource(iconResource); 27521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (item.hasIconLevel()) { 27621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng icon.setImageLevel(item.getIconLevel()); 27721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 27821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 27921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 28021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 28121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng private class VerticalListAdapter extends RecyclerView.Adapter { 28221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng private SortedList mItems; 28321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng private final ActionListener mActionListener; 28421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 28521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public VerticalListAdapter(ActionListener actionListener, List<ListItem> choices) { 28621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng super(); 28721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng mActionListener = actionListener; 28821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng ListItemComparator comparator = new ListItemComparator(); 28921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng mItems = new SortedList<ListItem>( 29021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng ListItem.class, new SortedListAdapterCallback<ListItem>(this) { 29121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng @Override 29221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public int compare(ListItem t0, ListItem t1) { 29321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return comparator.compare(t0, t1); 29421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 29521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 29621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng @Override 29721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public boolean areContentsTheSame(ListItem oldItem, ListItem newItem) { 298f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng return comparator.compare(oldItem, newItem) == 0; 29921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 30021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 30121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng @Override 30221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public boolean areItemsTheSame(ListItem item1, ListItem item2) { 30321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return item1.equals(item2); 30421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 30521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng }); 30621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng mItems.addAll(choices.toArray(new ListItem[0]), false); 30721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 30821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 30921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng private View.OnClickListener createClickListener(final ListItem item) { 31021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return new View.OnClickListener() { 31121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng @Override 31221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public void onClick(View v) { 31321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (v == null || v.getWindowToken() == null || mActionListener == null) { 31421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return; 31521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 31621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng mActionListener.onClick(item); 31721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 31821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng }; 31921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 32021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 32121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng private View.OnFocusChangeListener createFocusListener(final ListItem item) { 32221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return new View.OnFocusChangeListener() { 32321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng @Override 32421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public void onFocusChange(View v, boolean hasFocus) { 32521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (v == null || v.getWindowToken() == null || mActionListener == null 32621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng || !hasFocus) { 32721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return; 32821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 32921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng mActionListener.onFocus(item); 33021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 33121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng }; 33221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 33321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 33421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng @Override 33521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 33621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng LayoutInflater inflater = (LayoutInflater) parent.getContext().getSystemService( 33721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng Context.LAYOUT_INFLATER_SERVICE); 33821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng View v = inflater.inflate(R.layout.setup_list_item, parent, false); 33921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return new ListItemViewHolder(v); 34021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 34121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 34221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng @Override 34321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public void onBindViewHolder(RecyclerView.ViewHolder baseHolder, int position) { 34421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (position >= mItems.size()) { 34521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return; 34621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 34721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 34821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng ListItemViewHolder viewHolder = (ListItemViewHolder) baseHolder; 34921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng ListItem item = (ListItem) mItems.get(position); 35021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng viewHolder.init((ListItem) item, createClickListener(item), createFocusListener(item)); 35121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 35221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 35321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public SortedList<ListItem> getItems() { 35421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return mItems; 35521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 35621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 35721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng @Override 35821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public int getItemCount() { 35921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng return mItems.size(); 36021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 36121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 36221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public void updateItems(List<ListItem> inputItems) { 36321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng TreeSet<ListItem> newItemSet = new TreeSet<ListItem>(new ListItemComparator()); 36421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng for (ListItem item: inputItems) { 36521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng newItemSet.add(item); 36621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 36721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng ArrayList<ListItem> toRemove = new ArrayList<ListItem>(); 36821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng for (int j = 0 ; j < mItems.size(); j++) { 36921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng ListItem oldItem = (ListItem) mItems.get(j); 37021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (!newItemSet.contains(oldItem)) { 37121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng toRemove.add(oldItem); 37221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 37321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 37421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng for (ListItem item: toRemove) { 37521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng mItems.remove(item); 37621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 37721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng mItems.addAll(inputItems.toArray(new ListItem[0]), true); 37821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 37921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 38021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 38165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final String EXTRA_TITLE = "title"; 38265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final String EXTRA_DESCRIPTION = "description"; 38365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final String EXTRA_LIST_ELEMENTS = "list_elements"; 38465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final String EXTRA_LAST_SELECTION = "last_selection"; 385f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng private static final int SELECT_ITEM_DELAY = 100; 38665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 38765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public static SelectFromListWizardFragment newInstance(String title, String description, 38865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ArrayList<ListItem> listElements, ListItem lastSelection) { 38965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane SelectFromListWizardFragment fragment = new SelectFromListWizardFragment(); 39065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Bundle args = new Bundle(); 39165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane args.putString(EXTRA_TITLE, title); 39265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane args.putString(EXTRA_DESCRIPTION, description); 39365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane args.putParcelableArrayList(EXTRA_LIST_ELEMENTS, listElements); 39465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane args.putParcelable(EXTRA_LAST_SELECTION, lastSelection); 39565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane fragment.setArguments(args); 39665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return fragment; 39765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 39865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 39965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private Handler mHandler; 40065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private View mMainView; 40121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng private VerticalGridView mListView; 40221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng private String mLastSelectedName; 403f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng private OnPreDrawListener mOnListPreDrawListener; 404f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng private Runnable mSelectItemRunnable; 40521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 40621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng private void updateSelected(String lastSelectionName) { 40721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng SortedList<ListItem> items = ((VerticalListAdapter) mListView.getAdapter()).getItems(); 40821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng for (int i = 0; i < items.size(); i++) { 40921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng ListItem item = (ListItem) items.get(i); 41044ce0a96ae3043039a231fac44607df20d3186afPowei Feng if (TextUtils.equals(lastSelectionName, item.getName())) { 41121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng mListView.setSelectedPosition(i); 41221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng break; 41365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 41465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 415f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng mLastSelectedName = lastSelectionName; 41665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 41765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 41821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public void update(List<ListItem> listElements) { 419f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng // We want keep the highlight on the same selected item from before the update. This is 420f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng // currently not possible (b/28120126). So we post a runnable to run after the update 421f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng // completes. 422f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng if (mSelectItemRunnable != null) { 423f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng mHandler.removeCallbacks(mSelectItemRunnable); 424f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng } 425f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng 426f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng final String lastSelected = mLastSelectedName; 427f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng mSelectItemRunnable = () -> { 428f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng updateSelected(lastSelected); 429f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng if (mOnListPreDrawListener != null) { 430f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng mListView.getViewTreeObserver().removeOnPreDrawListener(mOnListPreDrawListener); 431f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng mOnListPreDrawListener = null; 432f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng } 433f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng mSelectItemRunnable = null; 434f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng }; 435f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng 436f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng if (mOnListPreDrawListener != null) { 437f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng mListView.getViewTreeObserver().removeOnPreDrawListener(mOnListPreDrawListener); 438f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng } 439f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng 440f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng mOnListPreDrawListener = () -> { 441f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng mHandler.removeCallbacks(mSelectItemRunnable); 442f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng // Pre-draw can be called multiple times per update. We delay the runnable to select 443f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng // the item so that it will only run after the last pre-draw of this batch of update. 444f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng mHandler.postDelayed(mSelectItemRunnable, SELECT_ITEM_DELAY); 445f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng return true; 446f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng }; 447f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng 448f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng mListView.getViewTreeObserver().addOnPreDrawListener(mOnListPreDrawListener); 449f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng ((VerticalListAdapter) mListView.getAdapter()).updateItems(listElements); 45021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 45121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 45265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 45365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle) { 45421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng Resources resources = getContext().getResources(); 45521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 45665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mHandler = new Handler(); 45765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mMainView = inflater.inflate(R.layout.account_content_area, container, false); 4586316b89e65828d537da309851529d1295efd5730Tony Mantler 4596316b89e65828d537da309851529d1295efd5730Tony Mantler final ViewGroup descriptionArea = (ViewGroup) mMainView.findViewById(R.id.description); 4606316b89e65828d537da309851529d1295efd5730Tony Mantler final View content = inflater.inflate(R.layout.wifi_content, descriptionArea, false); 4616316b89e65828d537da309851529d1295efd5730Tony Mantler descriptionArea.addView(content); 4626316b89e65828d537da309851529d1295efd5730Tony Mantler 4636316b89e65828d537da309851529d1295efd5730Tony Mantler final ViewGroup actionArea = (ViewGroup) mMainView.findViewById(R.id.action); 46465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 46565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane TextView titleText = (TextView) content.findViewById(R.id.title_text); 46665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane TextView descriptionText = (TextView) content.findViewById(R.id.description_text); 46765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 46865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Bundle args = getArguments(); 46965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane String title = args.getString(EXTRA_TITLE); 47065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane String description = args.getString(EXTRA_DESCRIPTION); 47165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 47265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane boolean forceFocusable = AccessibilityHelper.forceFocusableViews(getActivity()); 47365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (title != null) { 47465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane titleText.setText(title); 47565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane titleText.setVisibility(View.VISIBLE); 47665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (forceFocusable) { 47765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane titleText.setFocusable(true); 47865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane titleText.setFocusableInTouchMode(true); 47965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 48065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 48165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane titleText.setVisibility(View.GONE); 48265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 48365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 48465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (description != null) { 48565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane descriptionText.setText(description); 48665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane descriptionText.setVisibility(View.VISIBLE); 48765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (forceFocusable) { 48865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane descriptionText.setFocusable(true); 48965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane descriptionText.setFocusableInTouchMode(true); 49065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 49165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 49265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane descriptionText.setVisibility(View.GONE); 49365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 49465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 49521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng ArrayList<ListItem> listItems = args.getParcelableArrayList(EXTRA_LIST_ELEMENTS); 49665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 49721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng mListView = 49821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng (VerticalGridView) inflater.inflate(R.layout.setup_list_view, actionArea, false); 49921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng mListView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE); 50021e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng mListView.setWindowAlignmentOffsetPercent( 50121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng resources.getFloat(R.dimen.setup_scroll_list_window_offset_percent)); 50221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng 50321e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng actionArea.addView(mListView); 50421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng ActionListener actionListener = new ActionListener() { 50565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 50621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public void onClick(ListItem item) { 50765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Activity a = getActivity(); 50848fce31d5176b2f4100da514dd46a45f24e41c84Tony Mantler if (a instanceof Listener && isResumed()) { 50921e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng ((Listener) a).onListSelectionComplete(item); 51065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 51165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 51265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 51365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 51421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng public void onFocus(ListItem item) { 51565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Activity a = getActivity(); 51621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng mLastSelectedName = item.getName(); 51765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (a instanceof Listener) { 51821e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng ((Listener) a).onListFocusChanged(item); 51965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 52065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 52121e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng }; 52221e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng mListView.setAdapter(new VerticalListAdapter(actionListener, listItems)); 52365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 52421e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng ListItem lastSelection = args.getParcelable(EXTRA_LAST_SELECTION); 52521e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng if (lastSelection != null) { 52621e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng updateSelected(lastSelection.getName()); 52721e8c04b87d6cdf30547fed13a1f7ddf606438f9Powei Feng } 52865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return mMainView; 52965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 53065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 53165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 532f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng public void onPause() { 533f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng super.onPause(); 534f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng if (mSelectItemRunnable != null) { 535f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng mHandler.removeCallbacks(mSelectItemRunnable); 536f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng mSelectItemRunnable = null; 537f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng } 538f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng if (mOnListPreDrawListener != null) { 539f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng mListView.getViewTreeObserver().removeOnPreDrawListener(mOnListPreDrawListener); 540f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng mOnListPreDrawListener = null; 541f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng } 542f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng } 543f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng 544f95e0a8d4a27d101dc4c42a2989c553d306f2033Powei Feng @Override 54565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void onResume() { 54665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane super.onResume(); 54765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mHandler.post(new Runnable() { 54865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 54965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void run() { 55065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane InputMethodManager inputMethodManager = (InputMethodManager) getActivity() 55165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane .getSystemService(Context.INPUT_METHOD_SERVICE); 55265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane inputMethodManager.hideSoftInputFromWindow( 55365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mMainView.getApplicationWindowToken(), 0); 55465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 55565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane }); 55665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 55765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane} 558