Home | History | Annotate | Download | only in editor
      1 /*
      2  * Copyright (C) 2009 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.contacts.editor;
     18 
     19 import android.os.Bundle;
     20 import android.os.Parcel;
     21 import android.os.Parcelable;
     22 
     23 import com.android.contacts.common.model.RawContactDelta;
     24 import com.android.contacts.common.model.ValuesDelta;
     25 import com.android.contacts.common.model.dataitem.DataKind;
     26 
     27 /**
     28  * A class that provides unique view ids for {@link ContentEditorView}, {@link KindSectionView},
     29  * {@link LabeledEditorView} and {@link EditView} on {@link EditContactActivity}.
     30  * It is used to assign a unique but consistent id to each view across {@link EditContactActivity}'s
     31  * lifecycle, so that we can re-construct view state (e.g. focused view) when the screen rotates.
     32  *
     33  * <p>This class is not thread safe.
     34  */
     35 public final class ViewIdGenerator implements Parcelable {
     36     private static final int INVALID_VIEW_ID = 0;
     37     private static final int INITIAL_VIEW_ID = 1;
     38 
     39     public static final int NO_VIEW_INDEX = -1;
     40 
     41     private int mNextId;
     42 
     43     /**
     44      * Used as a map from the "key" of the views to actual ids.  {@link #getId()} generates keys for
     45      * the views.
     46      */
     47     private Bundle mIdMap = new Bundle();
     48 
     49     private static final char KEY_SEPARATOR = '*';
     50 
     51     private final static StringBuilder sWorkStringBuilder = new StringBuilder();
     52 
     53     public ViewIdGenerator() {
     54         mNextId = INITIAL_VIEW_ID;
     55     }
     56 
     57     /** {@inheritDoc} */
     58     public int describeContents() {
     59         return 0;
     60     }
     61 
     62     /**
     63      * Returns an id for a view associated with specified contact field.
     64      *
     65      * @param entity {@link RawContactDelta} associated with the view
     66      * @param kind {@link DataKind} associated with the view, or null if none exists.
     67      * @param values {@link ValuesDelta} associated with the view, or null if none exists.
     68      * @param viewIndex index of the view in the parent {@link Editor}, if it's a leave view.
     69      *     Otherwise, pass {@link #NO_VIEW_INDEX}.
     70      */
     71     public int getId(RawContactDelta entity, DataKind kind, ValuesDelta values,
     72             int viewIndex) {
     73         final String k = getMapKey(entity, kind, values, viewIndex);
     74 
     75         int id = mIdMap.getInt(k, INVALID_VIEW_ID);
     76         if (id == INVALID_VIEW_ID) {
     77             // Make sure the new id won't conflict with auto-generated ids by masking with 0xffff.
     78             id = (mNextId++) & 0xFFFF;
     79             mIdMap.putInt(k, id);
     80         }
     81         return id;
     82     }
     83 
     84     private static String getMapKey(RawContactDelta entity, DataKind kind, ValuesDelta values,
     85             int viewIndex) {
     86         sWorkStringBuilder.setLength(0);
     87         if (entity != null) {
     88             sWorkStringBuilder.append(entity.getValues().getId());
     89 
     90             if (kind != null) {
     91                 sWorkStringBuilder.append(KEY_SEPARATOR);
     92                 sWorkStringBuilder.append(kind.mimeType);
     93 
     94                 if (values != null) {
     95                     sWorkStringBuilder.append(KEY_SEPARATOR);
     96                     sWorkStringBuilder.append(values.getId());
     97 
     98                     if (viewIndex != NO_VIEW_INDEX) {
     99                         sWorkStringBuilder.append(KEY_SEPARATOR);
    100                         sWorkStringBuilder.append(viewIndex);
    101                     }
    102                 }
    103             }
    104         }
    105         return sWorkStringBuilder.toString();
    106     }
    107 
    108     /** {@Override} */
    109     public void writeToParcel(Parcel dest, int flags) {
    110         dest.writeInt(mNextId);
    111         dest.writeBundle(mIdMap);
    112     }
    113 
    114     private void readFromParcel(Parcel src) {
    115         mNextId = src.readInt();
    116         mIdMap = src.readBundle();
    117     }
    118 
    119     public static final Parcelable.Creator<ViewIdGenerator> CREATOR =
    120             new Parcelable.Creator<ViewIdGenerator>() {
    121         public ViewIdGenerator createFromParcel(Parcel in) {
    122             final ViewIdGenerator vig = new ViewIdGenerator();
    123             vig.readFromParcel(in);
    124             return vig;
    125         }
    126 
    127         public ViewIdGenerator[] newArray(int size) {
    128             return new ViewIdGenerator[size];
    129         }
    130     };
    131 }
    132