1171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan/*
2171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan * Copyright (C) 2016 The Android Open Source Project
3171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan *
4171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan * Licensed under the Apache License, Version 2.0 (the "License");
5171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan * you may not use this file except in compliance with the License.
6171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan * You may obtain a copy of the License at
7171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan *
8171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan *      http://www.apache.org/licenses/LICENSE-2.0
9171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan *
10171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan * Unless required by applicable law or agreed to in writing, software
11171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan * distributed under the License is distributed on an "AS IS" BASIS,
12171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan * See the License for the specific language governing permissions and
14171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan * limitations under the License.
15171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan */
16171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
17171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tanpackage com.android.documentsui.sorting;
18171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
19d9caa6ab53aa784acaf241c0ded3c4ae2d342bf8Steve McKayimport static com.android.documentsui.base.Shared.DEBUG;
2011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
21171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tanimport android.annotation.IntDef;
2211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tanimport android.annotation.Nullable;
23a4b68e5b5917c93c3f3c185ecd42db2596119220Steve McKayimport android.content.ContentResolver;
242010ff7828f2d68de0be24c975f5c48ec3151f96Garfield Tanimport android.database.Cursor;
2550b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKayimport android.os.Bundle;
26171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tanimport android.os.Parcel;
27171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tanimport android.os.Parcelable;
2811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tanimport android.provider.DocumentsContract.Document;
29b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tanimport android.support.annotation.VisibleForTesting;
3011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tanimport android.util.Log;
31171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tanimport android.util.SparseArray;
32171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tanimport android.view.View;
33171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
34171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tanimport com.android.documentsui.R;
35b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tanimport com.android.documentsui.base.Lookup;
3661f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tanimport com.android.documentsui.sorting.SortDimension.SortDirection;
37171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
38171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tanimport java.lang.annotation.Retention;
39171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tanimport java.lang.annotation.RetentionPolicy;
40171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tanimport java.util.ArrayList;
41171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tanimport java.util.Collection;
42171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tanimport java.util.List;
4311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tanimport java.util.function.Consumer;
44171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
45171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan/**
46171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan * Sort model that contains all columns and their sorting state.
47171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan */
48171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tanpublic class SortModel implements Parcelable {
49171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    @IntDef({
5011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            SORT_DIMENSION_ID_UNKNOWN,
51171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan            SORT_DIMENSION_ID_TITLE,
52171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan            SORT_DIMENSION_ID_SUMMARY,
53b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan            SORT_DIMENSION_ID_SIZE,
54b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan            SORT_DIMENSION_ID_FILE_TYPE,
55b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan            SORT_DIMENSION_ID_DATE
56171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    })
57171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    @Retention(RetentionPolicy.SOURCE)
58171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    public @interface SortDimensionId {}
5911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    public static final int SORT_DIMENSION_ID_UNKNOWN = 0;
60171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    public static final int SORT_DIMENSION_ID_TITLE = android.R.id.title;
61171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    public static final int SORT_DIMENSION_ID_SUMMARY = android.R.id.summary;
62171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    public static final int SORT_DIMENSION_ID_SIZE = R.id.size;
63b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan    public static final int SORT_DIMENSION_ID_FILE_TYPE = R.id.file_type;
64171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    public static final int SORT_DIMENSION_ID_DATE = R.id.date;
65171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
6661f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan    @IntDef(flag = true, value = {
6761f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan            UPDATE_TYPE_NONE,
6811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            UPDATE_TYPE_UNSPECIFIED,
6911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            UPDATE_TYPE_VISIBILITY,
7011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            UPDATE_TYPE_SORTING
7111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    })
7211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    @Retention(RetentionPolicy.SOURCE)
7311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    public @interface UpdateType {}
7411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    /**
7561f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan     * Default value for update type. Nothing is updated.
7611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     */
7761f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan    public static final int UPDATE_TYPE_NONE = 0;
7811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    /**
7911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     * Indicates the visibility of at least one dimension has changed.
8011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     */
81fe199cb1ae0a443c65111ee80daa05b9fafc48a6Garfield Tan    public static final int UPDATE_TYPE_VISIBILITY = 1;
8211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    /**
8311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     * Indicates the sorting order has changed, either because the sorted dimension has changed or
8411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     * the sort direction has changed.
8511d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     */
86fe199cb1ae0a443c65111ee80daa05b9fafc48a6Garfield Tan    public static final int UPDATE_TYPE_SORTING = 1 << 1;
8761f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan    /**
8861f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan     * Anything can be changed if the type is unspecified.
8961f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan     */
9061f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan    public static final int UPDATE_TYPE_UNSPECIFIED = -1;
9111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
9211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    private static final String TAG = "SortModel";
9311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
94171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    private final SparseArray<SortDimension> mDimensions;
95171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
96171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    private transient final List<UpdateListener> mListeners;
9711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    private transient Consumer<SortDimension> mMetricRecorder;
98171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
9911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    private int mDefaultDimensionId = SORT_DIMENSION_ID_UNKNOWN;
10011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    private boolean mIsUserSpecified = false;
10111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    private @Nullable SortDimension mSortedDimension;
102171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
103b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan    @VisibleForTesting
104b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan    SortModel(Collection<SortDimension> columns) {
105171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        mDimensions = new SparseArray<>(columns.size());
106171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
107171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        for (SortDimension column : columns) {
10811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            if (column.getId() == SORT_DIMENSION_ID_UNKNOWN) {
10911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                throw new IllegalArgumentException(
11011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                        "SortDimension id can't be " + SORT_DIMENSION_ID_UNKNOWN + ".");
11111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            }
112171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan            if (mDimensions.get(column.getId()) != null) {
113171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                throw new IllegalStateException(
114171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                        "SortDimension id must be unique. Duplicate id: " + column.getId());
115171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan            }
116171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan            mDimensions.put(column.getId(), column);
117171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        }
118171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
119171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        mListeners = new ArrayList<>();
120171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    }
121171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
122171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    public int getSize() {
123171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        return mDimensions.size();
124171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    }
125171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
126171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    public SortDimension getDimensionAt(int index) {
127171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        return mDimensions.valueAt(index);
128171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    }
129171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
13011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    public @Nullable SortDimension getDimensionById(int id) {
131171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        return mDimensions.get(id);
132171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    }
133171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
13411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    /**
13511d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     * Gets the sorted dimension id.
13611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     * @return the sorted dimension id or {@link #SORT_DIMENSION_ID_UNKNOWN} if there is no sorted
13711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     * dimension.
13811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     */
13911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    public int getSortedDimensionId() {
14011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        return mSortedDimension != null ? mSortedDimension.getId() : SORT_DIMENSION_ID_UNKNOWN;
141171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    }
142171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
14361f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan    public @SortDirection int getCurrentSortDirection() {
14461f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan        return mSortedDimension != null
14561f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan                ? mSortedDimension.getSortDirection()
14661f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan                : SortDimension.SORT_DIRECTION_NONE;
14761f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan    }
14861f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan
14911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    /**
15011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     * Sort by the default direction of the given dimension if user has never specified any sort
15111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     * direction before.
15211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     * @param dimensionId the id of the dimension
15311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     */
15411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    public void setDefaultDimension(int dimensionId) {
15511d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        final boolean mayNeedSorting = (mDefaultDimensionId != dimensionId);
15611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
15711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        mDefaultDimensionId = dimensionId;
15811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
15911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        if (mayNeedSorting) {
16011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            sortOnDefault();
16111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        }
16211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    }
16311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
16411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    void setMetricRecorder(Consumer<SortDimension> metricRecorder) {
16511d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        mMetricRecorder = metricRecorder;
16611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    }
16711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
16811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    /**
16911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     * Sort by given dimension and direction. Should only be used when user explicitly asks to sort
17011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     * docs.
17111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     * @param dimensionId the id of the dimension
17211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     * @param direction the direction to sort docs in
17311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     */
17461f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan    public void sortByUser(int dimensionId, @SortDirection int direction) {
17511d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        SortDimension dimension = mDimensions.get(dimensionId);
17611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        if (dimension == null) {
17711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            throw new IllegalArgumentException("Unknown column id: " + dimensionId);
17811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        }
17911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
18011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        sortByDimension(dimension, direction);
18111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
18211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        if (mMetricRecorder != null) {
18311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            mMetricRecorder.accept(dimension);
18411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        }
18511d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
18611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        mIsUserSpecified = true;
18711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    }
18811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
18911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    private void sortByDimension(
19061f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan            SortDimension newSortedDimension, @SortDirection int direction) {
19111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        if (newSortedDimension == mSortedDimension
19211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                && mSortedDimension.mSortDirection == direction) {
19311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            // Sort direction not changed, no need to proceed.
19411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            return;
195171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        }
196171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
19711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        if ((newSortedDimension.getSortCapability() & direction) == 0) {
198171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan            throw new IllegalStateException(
19911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                    "Dimension with id: " + newSortedDimension.getId()
20011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                    + " can't be sorted in direction:" + direction);
201171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        }
20211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
203171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        switch (direction) {
204171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan            case SortDimension.SORT_DIRECTION_ASCENDING:
205171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan            case SortDimension.SORT_DIRECTION_DESCENDING:
206171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                newSortedDimension.mSortDirection = direction;
207171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                break;
208171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan            default:
209171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                throw new IllegalArgumentException("Unknown sort direction: " + direction);
210171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        }
211171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
212171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        if (mSortedDimension != null && mSortedDimension != newSortedDimension) {
213171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan            mSortedDimension.mSortDirection = SortDimension.SORT_DIRECTION_NONE;
214171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        }
215171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
216171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        mSortedDimension = newSortedDimension;
217171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
21811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        notifyListeners(UPDATE_TYPE_SORTING);
219171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    }
220171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
221171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    public void setDimensionVisibility(int columnId, int visibility) {
222171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        assert(mDimensions.get(columnId) != null);
223171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
224171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        mDimensions.get(columnId).mVisibility = visibility;
225171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
22611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        notifyListeners(UPDATE_TYPE_VISIBILITY);
22711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    }
22811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
229b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan    public Cursor sortCursor(Cursor cursor, Lookup<String, String> fileTypesMap) {
2302010ff7828f2d68de0be24c975f5c48ec3151f96Garfield Tan        if (mSortedDimension != null) {
231b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan            return new SortingCursorWrapper(cursor, mSortedDimension, fileTypesMap);
2322010ff7828f2d68de0be24c975f5c48ec3151f96Garfield Tan        } else {
2332010ff7828f2d68de0be24c975f5c48ec3151f96Garfield Tan            return cursor;
2342010ff7828f2d68de0be24c975f5c48ec3151f96Garfield Tan        }
2352010ff7828f2d68de0be24c975f5c48ec3151f96Garfield Tan    }
2362010ff7828f2d68de0be24c975f5c48ec3151f96Garfield Tan
23750b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay    public void addQuerySortArgs(Bundle queryArgs) {
23898f8c5f502e049a6b85439d773949cdbaa0f78aeSteve McKay        // should only be called when R.bool.feature_content_paging is true
23950b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay
24011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        final int id = getSortedDimensionId();
24111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        switch (id) {
24261f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan            case SORT_DIMENSION_ID_UNKNOWN:
24350b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                return;
24411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            case SortModel.SORT_DIMENSION_ID_TITLE:
24550b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                queryArgs.putStringArray(
24650b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                        ContentResolver.QUERY_ARG_SORT_COLUMNS,
24750b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                        new String[]{ Document.COLUMN_DISPLAY_NAME });
24811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                break;
24911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            case SortModel.SORT_DIMENSION_ID_DATE:
25050b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                queryArgs.putStringArray(
25150b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                        ContentResolver.QUERY_ARG_SORT_COLUMNS,
25250b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                        new String[]{ Document.COLUMN_LAST_MODIFIED });
25311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                break;
25411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            case SortModel.SORT_DIMENSION_ID_SIZE:
25550b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                queryArgs.putStringArray(
25650b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                        ContentResolver.QUERY_ARG_SORT_COLUMNS,
25750b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                        new String[]{ Document.COLUMN_SIZE });
25811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                break;
25998d745d90b2bf8232593f2d5f9092536298d1147Garfield Tan            case SortModel.SORT_DIMENSION_ID_FILE_TYPE:
26098d745d90b2bf8232593f2d5f9092536298d1147Garfield Tan                // Unfortunately sorting by mime type is pretty much guaranteed different from
26198d745d90b2bf8232593f2d5f9092536298d1147Garfield Tan                // sorting by user-friendly type, so there is no point to guide the provider to sort
26298d745d90b2bf8232593f2d5f9092536298d1147Garfield Tan                // in a particular order.
26398d745d90b2bf8232593f2d5f9092536298d1147Garfield Tan                return;
26411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            default:
26511d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                throw new IllegalStateException(
26611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                        "Unexpected sort dimension id: " + id);
26711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        }
26811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
26911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        final SortDimension dimension = getDimensionById(id);
27011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        switch (dimension.getSortDirection()) {
27111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            case SortDimension.SORT_DIRECTION_ASCENDING:
27250b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                queryArgs.putInt(
27350b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                        ContentResolver.QUERY_ARG_SORT_DIRECTION,
27450b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                        ContentResolver.QUERY_SORT_DIRECTION_ASCENDING);
27511d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                break;
27611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            case SortDimension.SORT_DIRECTION_DESCENDING:
27750b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                queryArgs.putInt(
27850b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                        ContentResolver.QUERY_ARG_SORT_DIRECTION,
27950b9baedc04a226b7a2e21f81f9a87533e3f7d02Steve McKay                        ContentResolver.QUERY_SORT_DIRECTION_DESCENDING);
28011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                break;
28111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            default:
28211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                throw new IllegalStateException(
28311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                        "Unexpected sort direction: " + dimension.getSortDirection());
28411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        }
285171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    }
286171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
287f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay    public @Nullable String getDocumentSortQuery() {
288710248d5ee766765b86fa36fe2ddd8d65f926755Steve McKay        // This method should only be called when R.bool.feature_content_paging exists.
289710248d5ee766765b86fa36fe2ddd8d65f926755Steve McKay        // Once that feature is enabled by default (and reference removed), this method
290710248d5ee766765b86fa36fe2ddd8d65f926755Steve McKay        // should also be removed.
291710248d5ee766765b86fa36fe2ddd8d65f926755Steve McKay        // The following log message exists simply to make reference to
292710248d5ee766765b86fa36fe2ddd8d65f926755Steve McKay        // R.bool.feature_content_paging so that compiler will fail when value
293710248d5ee766765b86fa36fe2ddd8d65f926755Steve McKay        // is remove from config.xml.
2945918a06c126f3554d33b0b36a0b4c21f3dbc91beSteve McKay        int readTheCommentAbove = R.bool.feature_content_paging;
295f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay
296f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay        final int id = getSortedDimensionId();
297f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay        final String columnName;
298f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay        switch (id) {
299f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay            case SORT_DIMENSION_ID_UNKNOWN:
300f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay                return null;
301f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay            case SortModel.SORT_DIMENSION_ID_TITLE:
302f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay                columnName = Document.COLUMN_DISPLAY_NAME;
303f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay                break;
304f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay            case SortModel.SORT_DIMENSION_ID_DATE:
305f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay                columnName = Document.COLUMN_LAST_MODIFIED;
306f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay                break;
307f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay            case SortModel.SORT_DIMENSION_ID_SIZE:
308f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay                columnName = Document.COLUMN_SIZE;
309f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay                break;
31098d745d90b2bf8232593f2d5f9092536298d1147Garfield Tan            case SortModel.SORT_DIMENSION_ID_FILE_TYPE:
31198d745d90b2bf8232593f2d5f9092536298d1147Garfield Tan                // Unfortunately sorting by mime type is pretty much guaranteed different from
31298d745d90b2bf8232593f2d5f9092536298d1147Garfield Tan                // sorting by user-friendly type, so there is no point to guide the provider to sort
31398d745d90b2bf8232593f2d5f9092536298d1147Garfield Tan                // in a particular order.
31498d745d90b2bf8232593f2d5f9092536298d1147Garfield Tan                return null;
315f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay            default:
316f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay                throw new IllegalStateException(
317f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay                        "Unexpected sort dimension id: " + id);
318f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay        }
319f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay
320f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay        final SortDimension dimension = getDimensionById(id);
321f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay        final String direction;
322f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay        switch (dimension.getSortDirection()) {
323f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay            case SortDimension.SORT_DIRECTION_ASCENDING:
324f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay                direction = " ASC";
325f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay                break;
326f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay            case SortDimension.SORT_DIRECTION_DESCENDING:
327f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay                direction = " DESC";
328f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay                break;
329f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay            default:
330f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay                throw new IllegalStateException(
331f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay                        "Unexpected sort direction: " + dimension.getSortDirection());
332f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay        }
333f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay
334f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay        return columnName + direction;
335f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay    }
336f208d84542605c76a060e3a2e76166bbd940b3bbSteve McKay
33711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    private void notifyListeners(@UpdateType int updateType) {
338171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        for (int i = mListeners.size() - 1; i >= 0; --i) {
33911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            mListeners.get(i).onModelUpdate(this, updateType);
340171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        }
341171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    }
342171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
343171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    public void addListener(UpdateListener listener) {
344171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        mListeners.add(listener);
345171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    }
346171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
347171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    public void removeListener(UpdateListener listener) {
348171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        mListeners.remove(listener);
349171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    }
350171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
35111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    /**
35211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     * Sort by default dimension and direction if there is no history of user specifying a sort
35311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     * order.
35411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan     */
35511d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    private void sortOnDefault() {
35611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        if (!mIsUserSpecified) {
35711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            SortDimension dimension = mDimensions.get(mDefaultDimensionId);
35811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            if (dimension == null) {
35911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                if (DEBUG) Log.d(TAG, "No default sort dimension.");
36011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                return;
36111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            }
36211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
36311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            sortByDimension(dimension, dimension.getDefaultSortDirection());
36411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        }
36511d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    }
36611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
36711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    @Override
36811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    public boolean equals(Object o) {
36911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        if (o == null || !(o instanceof SortModel)) {
37011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            return false;
37111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        }
37211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
37311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        if (this == o) {
37411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            return true;
37511d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        }
37611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
37711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        SortModel other = (SortModel) o;
37811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        if (mDimensions.size() != other.mDimensions.size()) {
37911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            return false;
38011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        }
38111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        for (int i = 0; i < mDimensions.size(); ++i) {
38211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            final SortDimension dimension = mDimensions.valueAt(i);
38311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            final int id = dimension.getId();
38411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            if (!dimension.equals(other.getDimensionById(id))) {
38511d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                return false;
38611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            }
38711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        }
38811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
38911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        return mDefaultDimensionId == other.mDefaultDimensionId
39011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                && (mSortedDimension == other.mSortedDimension
39111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                    || mSortedDimension.equals(other.mSortedDimension));
39211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    }
39311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
39411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    @Override
39511d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan    public String toString() {
39611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        return new StringBuilder()
39711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                .append("SortModel{")
398fe199cb1ae0a443c65111ee80daa05b9fafc48a6Garfield Tan                .append("dimensions=").append(mDimensions)
39911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                .append(", defaultDimensionId=").append(mDefaultDimensionId)
40011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                .append(", sortedDimension=").append(mSortedDimension)
40111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                .append("}")
40211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                .toString();
403171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    }
404171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
405171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    @Override
406171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    public int describeContents() {
407171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        return 0;
408171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    }
409171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
410171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    @Override
411171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    public void writeToParcel(Parcel out, int flag) {
412171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        out.writeInt(mDimensions.size());
413171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        for (int i = 0; i < mDimensions.size(); ++i) {
414171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan            out.writeParcelable(mDimensions.valueAt(i), flag);
415171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        }
41611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
41711d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        out.writeInt(mDefaultDimensionId);
41861f564beacafc5edebbb4b05d098203816ff7f64Garfield, Tan        out.writeInt(getSortedDimensionId());
419171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    }
420171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
421171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    public static Parcelable.Creator<SortModel> CREATOR = new Parcelable.Creator<SortModel>() {
422171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
423171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        @Override
424171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        public SortModel createFromParcel(Parcel in) {
42511d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            final int size = in.readInt();
426171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan            Collection<SortDimension> columns = new ArrayList<>(size);
427171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan            for (int i = 0; i < size; ++i) {
428171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                columns.add(in.readParcelable(getClass().getClassLoader()));
429171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan            }
43011d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            SortModel model = new SortModel(columns);
43111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
43211d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            model.mDefaultDimensionId = in.readInt();
43311d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            model.mSortedDimension = model.getDimensionById(in.readInt());
43411d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan
43511d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan            return model;
436171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        }
437171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
438171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        @Override
439171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        public SortModel[] newArray(int size) {
440171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan            return new SortModel[size];
441171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        }
442171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    };
443171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
444171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    /**
445171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan     * Creates a model for all other roots.
446171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan     *
447171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan     * TODO: move definition of columns into xml, and inflate model from it.
448171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan     */
449171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    public static SortModel createModel() {
450171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        List<SortDimension> dimensions = new ArrayList<>(4);
451171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        SortDimension.Builder builder = new SortDimension.Builder();
452171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
453171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        // Name column
454171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        dimensions.add(builder
455171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withId(SORT_DIMENSION_ID_TITLE)
45611d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                .withLabelId(R.string.sort_dimension_name)
457171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withDataType(SortDimension.DATA_TYPE_STRING)
458171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withSortCapability(SortDimension.SORT_CAPABILITY_BOTH_DIRECTION)
459171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withDefaultSortDirection(SortDimension.SORT_DIRECTION_ASCENDING)
460171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withVisibility(View.VISIBLE)
461171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .build()
462171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        );
463171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
464171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        // Summary column
465171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        // Summary is only visible in Downloads and Recents root.
466171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        dimensions.add(builder
467171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withId(SORT_DIMENSION_ID_SUMMARY)
46811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                .withLabelId(R.string.sort_dimension_summary)
469171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withDataType(SortDimension.DATA_TYPE_STRING)
470171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withSortCapability(SortDimension.SORT_CAPABILITY_NONE)
471171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withVisibility(View.INVISIBLE)
472171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .build()
473171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        );
474171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
475171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        // Size column
476171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        dimensions.add(builder
477171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withId(SORT_DIMENSION_ID_SIZE)
47811d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                .withLabelId(R.string.sort_dimension_size)
479171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withDataType(SortDimension.DATA_TYPE_NUMBER)
480171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withSortCapability(SortDimension.SORT_CAPABILITY_BOTH_DIRECTION)
481171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withDefaultSortDirection(SortDimension.SORT_DIRECTION_ASCENDING)
482171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withVisibility(View.VISIBLE)
483171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .build()
484171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        );
485171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
486b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan        // Type column
487b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan        dimensions.add(builder
488b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan            .withId(SORT_DIMENSION_ID_FILE_TYPE)
489b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan            .withLabelId(R.string.sort_dimension_file_type)
490b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan            .withDataType(SortDimension.DATA_TYPE_STRING)
491b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan            .withSortCapability(SortDimension.SORT_CAPABILITY_BOTH_DIRECTION)
492b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan            .withDefaultSortDirection(SortDimension.SORT_DIRECTION_ASCENDING)
493b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan            .withVisibility(View.VISIBLE)
494b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan            .build());
495b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan
496171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        // Date column
497171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        dimensions.add(builder
498171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withId(SORT_DIMENSION_ID_DATE)
49911d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan                .withLabelId(R.string.sort_dimension_date)
500171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withDataType(SortDimension.DATA_TYPE_NUMBER)
501171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withSortCapability(SortDimension.SORT_CAPABILITY_BOTH_DIRECTION)
502171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withDefaultSortDirection(SortDimension.SORT_DIRECTION_DESCENDING)
503171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .withVisibility(View.VISIBLE)
504171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan                .build()
505171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        );
506171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
507171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan        return new SortModel(dimensions);
508171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    }
509171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan
510171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    public interface UpdateListener {
51111d23483bf28768c04c25e4056df648fa8301aefGarfield, Tan        void onModelUpdate(SortModel newModel, @UpdateType int updateType);
512171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan    }
513171e6f53d114c3fe5ee69bc4e2bafb53daa4bda5Garfield, Tan}
514