From acab44fc939b4083ab7ec889b0c6d4fe0db00cca Mon Sep 17 00:00:00 2001 From: cretin45 Date: Fri, 13 Nov 2015 16:51:43 -0800 Subject: Reimplement the CM scrubber against the new Launcher PS4: Implement RTL support Change-Id: I4456d54b5924913d1b36e1cfa9a2269150f6fb3e --- .../launcher3/BaseRecyclerViewScrubberSection.java | 267 +++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 src/com/android/launcher3/BaseRecyclerViewScrubberSection.java (limited to 'src/com/android/launcher3/BaseRecyclerViewScrubberSection.java') diff --git a/src/com/android/launcher3/BaseRecyclerViewScrubberSection.java b/src/com/android/launcher3/BaseRecyclerViewScrubberSection.java new file mode 100644 index 000000000..1d17ea887 --- /dev/null +++ b/src/com/android/launcher3/BaseRecyclerViewScrubberSection.java @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2015 The CyanogenMod 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.launcher3; + +import android.text.TextUtils; +import android.util.Log; +import android.util.SparseArray; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; + +public class BaseRecyclerViewScrubberSection { + private static final String TAG = "BRVScrubberSections"; + private static final String ALPHA_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + private static final int MAX_NUMBER_CUSTOM_SECTIONS = 8; + private static final int MAX_SECTIONS = ALPHA_LETTERS.length() + MAX_NUMBER_CUSTOM_SECTIONS; + public static final int INVALID_INDEX = -1; + + private AutoExpandTextView.HighlightedText mHighlightedText; + private int mPreviousValidIndex; + private int mNextValidIndex; + private int mAdapterIndex; + + public BaseRecyclerViewScrubberSection(String text, boolean highlight, int idx) { + mHighlightedText = new AutoExpandTextView.HighlightedText(text, highlight); + mAdapterIndex = idx; + mPreviousValidIndex = mNextValidIndex = idx; + } + + public boolean getHighlight() { + return mHighlightedText.mHighlight; + } + + public String getText() { + return mHighlightedText.mText; + } + + public int getPreviousIndex() { + return mPreviousValidIndex; + } + + public int getNextIndex() { + return mNextValidIndex; + } + + public int getAdapterIndex() { + return mAdapterIndex; + } + + private static int + getFirstValidIndex(RtlIndexArrayList sections, + boolean isRtl) { + for (int i = 0; i < sections.size(); i++) { + if (sections.get(i, isRtl).getHighlight()) { + return i; + } + } + + return INVALID_INDEX; + } + + private static void createIndices(RtlIndexArrayList sections, + boolean isRtl) { + if (sections == null || sections.size() == 0) { + return; + } + + // walk forwards and fill out the previous valid index based on the previous highlight + int currentIdx = getFirstValidIndex(sections, isRtl); + for (int i = 0; i < sections.size(); i++) { + if (sections.get(i, isRtl).getHighlight()) { + currentIdx = i; + } + + sections.get(i, isRtl).mPreviousValidIndex = currentIdx; + } + + // currentIdx should be now on the last valid index so walk back and fill the other way + for (int i = sections.size() - 1; i >= 0; i--) { + if (sections.get(i, isRtl).getHighlight()) { + currentIdx = i; + } + + sections.get(i, isRtl).mNextValidIndex = currentIdx; + } + } + + public static ArrayList getHighlightText( + RtlIndexArrayList sections) { + if (sections == null) { + return null; + } + + ArrayList highlights = new ArrayList<>(sections.size()); + for (BaseRecyclerViewScrubberSection section : sections) { + highlights.add(section.mHighlightedText); + } + + return highlights; + } + + private static void addAlphaLetters(RtlIndexArrayList sections, + HashMap foundAlphaLetters) { + for (int i = 0; i < ALPHA_LETTERS.length(); i++) { + boolean highlighted = foundAlphaLetters.containsKey(i); + int index = highlighted + ? foundAlphaLetters.get(i) : BaseRecyclerViewScrubberSection.INVALID_INDEX; + + sections.add(new BaseRecyclerViewScrubberSection(ALPHA_LETTERS.substring(i, i + 1), + highlighted, index)); + } + } + + /** + * Takes the sections and runs some checks to see if we can create a valid + * appDrawerScrubberSection out of it. This list will contain the original header list plus + * fill out the remaining sections based on the ALPHA_LETTERS. It will then determine which + * ones to highlight as well as what letters to highlight when scrolling over the + * grayed out sections + * @param sectionNames list of sectionName Strings + * @return the list of scrubber sections + */ + public static RtlIndexArrayList + createSections(String[] sectionNames, boolean isRtl) { + // check if we have a valid header section + if (!validSectionNameList(sectionNames)) { + return null; + } + + // this will track the mapping of ALPHA_LETTERS index to the headers index + HashMap foundAlphaLetters = new HashMap<>(); + RtlIndexArrayList sections = + new RtlIndexArrayList<>(sectionNames.length); + boolean inAlphaLetterSection = false; + + for (int i = 0; i < sectionNames.length; i++) { + int alphaLetterIndex = TextUtils.isEmpty(sectionNames[i]) + ? -1 : ALPHA_LETTERS.indexOf(sectionNames[i]); + + // if we found an ALPHA_LETTERS store that in foundAlphaLetters and continue + if (alphaLetterIndex >= 0) { + foundAlphaLetters.put(alphaLetterIndex, i); + inAlphaLetterSection = true; + } else { + // if we are exiting the ALPHA_LETTERS section, add it here + if (inAlphaLetterSection) { + addAlphaLetters(sections, foundAlphaLetters); + inAlphaLetterSection = false; + } + + // add the custom header + sections.add(new BaseRecyclerViewScrubberSection(sectionNames[i], true, i)); + } + } + + // if the last section are the alpha letters, then add it + if (inAlphaLetterSection) { + addAlphaLetters(sections, foundAlphaLetters); + } + + // create the forward and backwards indices for scrolling over the grayed out sections + BaseRecyclerViewScrubberSection.createIndices(sections, isRtl); + + return sections; + } + + /** + * Walk through the sectionNames and check for a few things: + * 1) No more than MAX_NUMBER_CUSTOM_SECTIONS sectionNames exist in the sectionNames list or no more + * than MAX_SECTIONS sectionNames exist in the list + * 2) the headers that fall in the ALPHA_LETTERS category are in the same order as ALPHA_LETTERS + * 3) There are no sectionNames that exceed length of 1 + * 4) The alpha letter sectionName is together and not separated by other things + */ + private static boolean validSectionNameList(String[] sectionNames) { + int numCustomSections = 0; + int previousAlphaIndex = -1; + boolean foundAlphaSections = false; + + for (String s : sectionNames) { + if (TextUtils.isEmpty(s)) { + numCustomSections++; + continue; + } + + if (s.length() > 1) { + Log.w(TAG, "Found section " + s + " with length: " + s.length()); + return false; + } + + int alphaIndex = ALPHA_LETTERS.indexOf(s); + if (alphaIndex >= 0) { + if (previousAlphaIndex != -1) { + // if the previous alpha index is >= alphaIndex then it is in the wrong order + if (previousAlphaIndex >= alphaIndex) { + Log.w(TAG, "Found letter index " + previousAlphaIndex + + " which is greater than " + alphaIndex); + return false; + } + } + + // if we've found headers previously and the index is -1 that means the alpha + // letters are separated out into two sections so return false + if (foundAlphaSections && previousAlphaIndex == -1) { + Log.w(TAG, "Found alpha letters twice"); + return false; + } + + previousAlphaIndex = alphaIndex; + foundAlphaSections = true; + } else { + numCustomSections++; + previousAlphaIndex = -1; + } + } + + final int listSize = foundAlphaSections + ? numCustomSections + ALPHA_LETTERS.length() + : numCustomSections; + + // if one of these conditions are satisfied, then return true + if (numCustomSections <= MAX_NUMBER_CUSTOM_SECTIONS || listSize <= MAX_SECTIONS) { + return true; + } + + if (numCustomSections > MAX_NUMBER_CUSTOM_SECTIONS) { + Log.w(TAG, "Found " + numCustomSections + "# custom sections when " + + MAX_NUMBER_CUSTOM_SECTIONS + " is allowed!"); + } else if (listSize > MAX_SECTIONS) { + Log.w(TAG, "Found " + listSize + " sections when " + + MAX_SECTIONS + " is allowed!"); + } + + return false; + } + + public static class RtlIndexArrayList extends ArrayList { + + public RtlIndexArrayList(int capacity) { + super(capacity); + } + + public T get(int index, boolean isRtl) { + if (isRtl) { + index = size() - 1 - index; + } + return super.get(index); + } + } +} \ No newline at end of file -- cgit v1.2.3