Home | History | Annotate | Download | only in documentsui
      1 /*
      2  * Copyright (C) 2013 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.documentsui;
     18 
     19 import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_DISPLAY_NAME;
     20 import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
     21 import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_SIZE;
     22 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
     23 import static com.android.documentsui.model.DocumentInfo.getCursorString;
     24 
     25 import android.database.AbstractCursor;
     26 import android.database.Cursor;
     27 import android.os.Bundle;
     28 import android.provider.DocumentsContract.Document;
     29 
     30 import com.android.documentsui.model.DocumentInfo;
     31 
     32 /**
     33  * Cursor wrapper that presents a sorted view of the underlying cursor. Handles
     34  * common {@link Document} sorting modes, such as ordering directories first.
     35  */
     36 public class SortingCursorWrapper extends AbstractCursor {
     37     private final Cursor mCursor;
     38 
     39     private final int[] mPosition;
     40     private final String[] mValueString;
     41     private final long[] mValueLong;
     42 
     43     public SortingCursorWrapper(Cursor cursor, int sortOrder) {
     44         mCursor = cursor;
     45 
     46         final int count = cursor.getCount();
     47         mPosition = new int[count];
     48         switch (sortOrder) {
     49             case SORT_ORDER_DISPLAY_NAME:
     50                 mValueString = new String[count];
     51                 mValueLong = null;
     52                 break;
     53             case SORT_ORDER_LAST_MODIFIED:
     54             case SORT_ORDER_SIZE:
     55                 mValueString = null;
     56                 mValueLong = new long[count];
     57                 break;
     58             default:
     59                 throw new IllegalArgumentException();
     60         }
     61 
     62         cursor.moveToPosition(-1);
     63         for (int i = 0; i < count; i++) {
     64             cursor.moveToNext();
     65             mPosition[i] = i;
     66 
     67             switch (sortOrder) {
     68                 case SORT_ORDER_DISPLAY_NAME:
     69                     final String mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
     70                     final String displayName = getCursorString(
     71                             cursor, Document.COLUMN_DISPLAY_NAME);
     72                     if (Document.MIME_TYPE_DIR.equals(mimeType)) {
     73                         mValueString[i] = DocumentInfo.DIR_PREFIX + displayName;
     74                     } else {
     75                         mValueString[i] = displayName;
     76                     }
     77                     break;
     78                 case SORT_ORDER_LAST_MODIFIED:
     79                     mValueLong[i] = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
     80                     break;
     81                 case SORT_ORDER_SIZE:
     82                     mValueLong[i] = getCursorLong(cursor, Document.COLUMN_SIZE);
     83                     break;
     84             }
     85         }
     86 
     87         switch (sortOrder) {
     88             case SORT_ORDER_DISPLAY_NAME:
     89                 synchronized (SortingCursorWrapper.class) {
     90 
     91                     binarySort(mPosition, mValueString);
     92                 }
     93                 break;
     94             case SORT_ORDER_LAST_MODIFIED:
     95             case SORT_ORDER_SIZE:
     96                 binarySort(mPosition, mValueLong);
     97                 break;
     98         }
     99     }
    100 
    101     @Override
    102     public Bundle getExtras() {
    103         return mCursor.getExtras();
    104     }
    105 
    106     @Override
    107     public void close() {
    108         super.close();
    109         mCursor.close();
    110     }
    111 
    112     @Override
    113     public boolean onMove(int oldPosition, int newPosition) {
    114         return mCursor.moveToPosition(mPosition[newPosition]);
    115     }
    116 
    117     @Override
    118     public String[] getColumnNames() {
    119         return mCursor.getColumnNames();
    120     }
    121 
    122     @Override
    123     public int getCount() {
    124         return mCursor.getCount();
    125     }
    126 
    127     @Override
    128     public double getDouble(int column) {
    129         return mCursor.getDouble(column);
    130     }
    131 
    132     @Override
    133     public float getFloat(int column) {
    134         return mCursor.getFloat(column);
    135     }
    136 
    137     @Override
    138     public int getInt(int column) {
    139         return mCursor.getInt(column);
    140     }
    141 
    142     @Override
    143     public long getLong(int column) {
    144         return mCursor.getLong(column);
    145     }
    146 
    147     @Override
    148     public short getShort(int column) {
    149         return mCursor.getShort(column);
    150     }
    151 
    152     @Override
    153     public String getString(int column) {
    154         return mCursor.getString(column);
    155     }
    156 
    157     @Override
    158     public int getType(int column) {
    159         return mCursor.getType(column);
    160     }
    161 
    162     @Override
    163     public boolean isNull(int column) {
    164         return mCursor.isNull(column);
    165     }
    166 
    167     /**
    168      * Borrowed from TimSort.binarySort(), but modified to sort two column
    169      * dataset.
    170      */
    171     private static void binarySort(int[] position, String[] value) {
    172         final int count = position.length;
    173         for (int start = 1; start < count; start++) {
    174             final int pivotPosition = position[start];
    175             final String pivotValue = value[start];
    176 
    177             int left = 0;
    178             int right = start;
    179 
    180             while (left < right) {
    181                 int mid = (left + right) >>> 1;
    182 
    183                 final String lhs = pivotValue;
    184                 final String rhs = value[mid];
    185                 final int compare = DocumentInfo.compareToIgnoreCaseNullable(lhs, rhs);
    186 
    187                 if (compare < 0) {
    188                     right = mid;
    189                 } else {
    190                     left = mid + 1;
    191                 }
    192             }
    193 
    194             int n = start - left;
    195             switch (n) {
    196                 case 2:
    197                     position[left + 2] = position[left + 1];
    198                     value[left + 2] = value[left + 1];
    199                 case 1:
    200                     position[left + 1] = position[left];
    201                     value[left + 1] = value[left];
    202                     break;
    203                 default:
    204                     System.arraycopy(position, left, position, left + 1, n);
    205                     System.arraycopy(value, left, value, left + 1, n);
    206             }
    207 
    208             position[left] = pivotPosition;
    209             value[left] = pivotValue;
    210         }
    211     }
    212 
    213     /**
    214      * Borrowed from TimSort.binarySort(), but modified to sort two column
    215      * dataset.
    216      */
    217     private static void binarySort(int[] position, long[] value) {
    218         final int count = position.length;
    219         for (int start = 1; start < count; start++) {
    220             final int pivotPosition = position[start];
    221             final long pivotValue = value[start];
    222 
    223             int left = 0;
    224             int right = start;
    225 
    226             while (left < right) {
    227                 int mid = (left + right) >>> 1;
    228 
    229                 final long lhs = pivotValue;
    230                 final long rhs = value[mid];
    231                 final int compare = Long.compare(lhs, rhs);
    232                 if (compare > 0) {
    233                     right = mid;
    234                 } else {
    235                     left = mid + 1;
    236                 }
    237             }
    238 
    239             int n = start - left;
    240             switch (n) {
    241                 case 2:
    242                     position[left + 2] = position[left + 1];
    243                     value[left + 2] = value[left + 1];
    244                 case 1:
    245                     position[left + 1] = position[left];
    246                     value[left + 1] = value[left];
    247                     break;
    248                 default:
    249                     System.arraycopy(position, left, position, left + 1, n);
    250                     System.arraycopy(value, left, value, left + 1, n);
    251             }
    252 
    253             position[left] = pivotPosition;
    254             value[left] = pivotValue;
    255         }
    256     }
    257 }
    258