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