blob: d352464b09ea1fc986f7848b10c7743af04475f4 [file] [log] [blame]
Craig Mautnerc00204b2013-03-05 15:02:14 -08001/*
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
17package com.android.server.wm;
18
19import android.graphics.Rect;
Craig Mautnera9a3fb12013-04-18 10:01:00 -070020import android.util.Slog;
Craig Mautnerc00204b2013-03-05 15:02:14 -080021
Craig Mautner9e4f28c2013-04-03 10:53:23 -070022import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
Craig Mautnera9a3fb12013-04-18 10:01:00 -070023import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
24import static com.android.server.wm.WindowManagerService.TAG;
Craig Mautner9e4f28c2013-04-03 10:53:23 -070025
Craig Mautner00af9fe2013-03-25 09:13:41 -070026import java.io.PrintWriter;
Craig Mautnerd9a22882013-03-16 15:00:36 -070027
Craig Mautnerc00204b2013-03-05 15:02:14 -080028public class StackBox {
Craig Mautner5a449152013-05-24 15:49:29 -070029 /** Used with {@link WindowManagerService#createStack}. Dependent on Configuration LTR/RTL. */
Craig Mautner05d29032013-05-03 13:40:13 -070030 public static final int TASK_STACK_GOES_BEFORE = 0;
Craig Mautner5a449152013-05-24 15:49:29 -070031 /** Used with {@link WindowManagerService#createStack}. Dependent on Configuration LTR/RTL. */
Craig Mautnerc00204b2013-03-05 15:02:14 -080032 public static final int TASK_STACK_GOES_AFTER = 1;
Craig Mautner5a449152013-05-24 15:49:29 -070033 /** Used with {@link WindowManagerService#createStack}. Horizontal to left of. */
34 public static final int TASK_STACK_TO_LEFT_OF = 2;
35 /** Used with {@link WindowManagerService#createStack}. Horizontal to right of. */
36 public static final int TASK_STACK_TO_RIGHT_OF = 3;
Craig Mautner967212c2013-04-13 21:10:58 -070037 /** Used with {@link WindowManagerService#createStack}. Vertical: lower t/b Rect values. */
Craig Mautner5a449152013-05-24 15:49:29 -070038 public static final int TASK_STACK_GOES_ABOVE = 4;
Craig Mautner967212c2013-04-13 21:10:58 -070039 /** Used with {@link WindowManagerService#createStack}. Vertical: higher t/b Rect values. */
Craig Mautner5a449152013-05-24 15:49:29 -070040 public static final int TASK_STACK_GOES_BELOW = 5;
Craig Mautner967212c2013-04-13 21:10:58 -070041 /** Used with {@link WindowManagerService#createStack}. Put on a higher layer on display. */
Craig Mautner5a449152013-05-24 15:49:29 -070042 public static final int TASK_STACK_GOES_OVER = 6;
Craig Mautner967212c2013-04-13 21:10:58 -070043 /** Used with {@link WindowManagerService#createStack}. Put on a lower layer on display. */
Craig Mautner5a449152013-05-24 15:49:29 -070044 public static final int TASK_STACK_GOES_UNDER = 7;
Craig Mautnerc00204b2013-03-05 15:02:14 -080045
Craig Mautner5ff12102013-05-24 12:50:15 -070046 static int sCurrentBoxId = 0;
47
48 /** Unique id for this box */
49 final int mStackBoxId;
50
Craig Mautner05d29032013-05-03 13:40:13 -070051 /** The service */
52 final WindowManagerService mService;
53
Craig Mautner00af9fe2013-03-25 09:13:41 -070054 /** The display this box sits in. */
Craig Mautnerc00204b2013-03-05 15:02:14 -080055 final DisplayContent mDisplayContent;
Craig Mautner00af9fe2013-03-25 09:13:41 -070056
57 /** Non-null indicates this is mFirst or mSecond of a parent StackBox. Null indicates this
58 * is this entire size of mDisplayContent. */
Craig Mautner4cd0c13f2013-04-16 15:55:52 -070059 StackBox mParent;
Craig Mautner00af9fe2013-03-25 09:13:41 -070060
61 /** First child, this is null exactly when mStack is non-null. */
Craig Mautnerc00204b2013-03-05 15:02:14 -080062 StackBox mFirst;
Craig Mautner00af9fe2013-03-25 09:13:41 -070063
64 /** Second child, this is null exactly when mStack is non-null. */
Craig Mautnerc00204b2013-03-05 15:02:14 -080065 StackBox mSecond;
Craig Mautner00af9fe2013-03-25 09:13:41 -070066
67 /** Stack of Tasks, this is null exactly when mFirst and mSecond are non-null. */
Craig Mautnerc00204b2013-03-05 15:02:14 -080068 TaskStack mStack;
Craig Mautner00af9fe2013-03-25 09:13:41 -070069
70 /** Content limits relative to the DisplayContent this sits in. */
Craig Mautner967212c2013-04-13 21:10:58 -070071 Rect mBounds = new Rect();
Craig Mautner00af9fe2013-03-25 09:13:41 -070072
73 /** Relative orientation of mFirst and mSecond. */
74 boolean mVertical;
75
Craig Mautner967212c2013-04-13 21:10:58 -070076 /** Fraction of mBounds to devote to mFirst, remainder goes to mSecond */
77 float mWeight;
78
Craig Mautner00af9fe2013-03-25 09:13:41 -070079 /** Dirty flag. Something inside this or some descendant of this has changed. */
Craig Mautnerc00204b2013-03-05 15:02:14 -080080 boolean layoutNeeded;
Craig Mautner00af9fe2013-03-25 09:13:41 -070081
Craig Mautnerd76dcdc2013-06-06 11:26:15 -070082 /** True if this StackBox sits below the Status Bar. */
83 boolean mUnderStatusBar;
84
Craig Mautner967212c2013-04-13 21:10:58 -070085 /** Used to keep from reallocating a temporary Rect for propagating bounds to child boxes */
86 Rect mTmpRect = new Rect();
87
Craig Mautner05d29032013-05-03 13:40:13 -070088 StackBox(WindowManagerService service, DisplayContent displayContent, StackBox parent) {
Craig Mautner5ff12102013-05-24 12:50:15 -070089 synchronized (StackBox.class) {
90 mStackBoxId = sCurrentBoxId++;
91 }
92
Craig Mautner05d29032013-05-03 13:40:13 -070093 mService = service;
Craig Mautnerc00204b2013-03-05 15:02:14 -080094 mDisplayContent = displayContent;
Craig Mautner967212c2013-04-13 21:10:58 -070095 mParent = parent;
Craig Mautnerc00204b2013-03-05 15:02:14 -080096 }
97
98 /** Propagate #layoutNeeded bottom up. */
99 void makeDirty() {
100 layoutNeeded = true;
101 if (mParent != null) {
102 mParent.makeDirty();
103 }
104 }
105
Craig Mautner00af9fe2013-03-25 09:13:41 -0700106 /**
Craig Mautner5a449152013-05-24 15:49:29 -0700107 * Determine if a particular StackBox is this one or a descendant of this one.
108 * @param stackBoxId The StackBox being searched for.
109 * @return true if the specified StackBox matches this or one of its descendants.
Craig Mautner00af9fe2013-03-25 09:13:41 -0700110 */
Craig Mautner5a449152013-05-24 15:49:29 -0700111 boolean contains(int stackBoxId) {
112 return mStackBoxId == stackBoxId || mFirst.contains(stackBoxId)
113 || mSecond.contains(stackBoxId);
Craig Mautner00af9fe2013-03-25 09:13:41 -0700114 }
115
Craig Mautnercf910b02013-04-23 11:23:27 -0700116 /**
117 * Return the stackId of the stack that intersects the passed point.
118 * @param x coordinate of point.
119 * @param y coordinate of point.
120 * @return -1 if point is outside of mBounds, otherwise the stackId of the containing stack.
121 */
122 int stackIdFromPoint(int x, int y) {
123 if (!mBounds.contains(x, y)) {
124 return -1;
125 }
126 if (mStack != null) {
127 return mStack.mStackId;
128 }
129 int stackId = mFirst.stackIdFromPoint(x, y);
130 if (stackId >= 0) {
131 return stackId;
132 }
133 return mSecond.stackIdFromPoint(x, y);
134 }
135
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700136 /** Determine if this StackBox is the first child or second child.
137 * @return true if this is the first child.
Craig Mautner967212c2013-04-13 21:10:58 -0700138 */
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700139 boolean isFirstChild() {
Craig Mautner05d29032013-05-03 13:40:13 -0700140 return mParent != null && mParent.mFirst == this;
Craig Mautner967212c2013-04-13 21:10:58 -0700141 }
142
143 /** Returns the bounds of the specified TaskStack if it is contained in this StackBox.
144 * @param stackId the TaskStack to find the bounds of.
145 * @return a new Rect with the bounds of stackId if it is within this StackBox, null otherwise.
146 */
147 Rect getStackBounds(int stackId) {
148 if (mStack != null) {
149 return mStack.mStackId == stackId ? new Rect(mBounds) : null;
150 }
151 Rect bounds = mFirst.getStackBounds(stackId);
152 if (bounds != null) {
153 return bounds;
154 }
155 return mSecond.getStackBounds(stackId);
156 }
157
Craig Mautner00af9fe2013-03-25 09:13:41 -0700158 /**
159 * Create a new TaskStack relative to a specified one by splitting the StackBox containing
160 * the specified TaskStack into two children. The size and position each of the new StackBoxes
161 * is determined by the passed parameters.
162 * @param stackId The id of the new TaskStack to create.
Craig Mautner5a449152013-05-24 15:49:29 -0700163 * @param relativeStackBoxId The id of the StackBox to place the new TaskStack next to.
Craig Mautner00af9fe2013-03-25 09:13:41 -0700164 * @param position One of the static TASK_STACK_GOES_xxx positions defined in this class.
165 * @param weight The percentage size of the parent StackBox to devote to the new TaskStack.
166 * @return The new TaskStack.
167 */
Craig Mautner5a449152013-05-24 15:49:29 -0700168 TaskStack split(int stackId, int relativeStackBoxId, int position, float weight) {
169 if (mStackBoxId != relativeStackBoxId) {
170 // This is not the targeted StackBox.
171 if (mStack != null) {
172 return null;
173 }
174 // Propagate the split to see if the targeted StackBox is in either sub box.
175 TaskStack stack = mFirst.split(stackId, relativeStackBoxId, position, weight);
Craig Mautner967212c2013-04-13 21:10:58 -0700176 if (stack != null) {
Craig Mautnerc00204b2013-03-05 15:02:14 -0800177 return stack;
178 }
Craig Mautner5a449152013-05-24 15:49:29 -0700179 return mSecond.split(stackId, relativeStackBoxId, position, weight);
Craig Mautnerc00204b2013-03-05 15:02:14 -0800180 }
181
Craig Mautner967212c2013-04-13 21:10:58 -0700182 // Found it!
Craig Mautner05d29032013-05-03 13:40:13 -0700183 TaskStack stack = new TaskStack(mService, stackId, mDisplayContent);
Craig Mautner967212c2013-04-13 21:10:58 -0700184 TaskStack firstStack;
185 TaskStack secondStack;
Craig Mautner5a449152013-05-24 15:49:29 -0700186 if (position == TASK_STACK_GOES_BEFORE) {
187 // TODO: Test Configuration here for LTR/RTL.
188 position = TASK_STACK_TO_LEFT_OF;
189 } else if (position == TASK_STACK_GOES_AFTER) {
190 // TODO: Test Configuration here for LTR/RTL.
191 position = TASK_STACK_TO_RIGHT_OF;
192 }
Craig Mautner967212c2013-04-13 21:10:58 -0700193 switch (position) {
194 default:
Craig Mautner5a449152013-05-24 15:49:29 -0700195 case TASK_STACK_TO_LEFT_OF:
196 case TASK_STACK_TO_RIGHT_OF:
Craig Mautner967212c2013-04-13 21:10:58 -0700197 mVertical = false;
Craig Mautner5a449152013-05-24 15:49:29 -0700198 if (position == TASK_STACK_TO_LEFT_OF) {
Craig Mautner967212c2013-04-13 21:10:58 -0700199 mWeight = weight;
200 firstStack = stack;
201 secondStack = mStack;
202 } else {
203 mWeight = 1.0f - weight;
204 firstStack = mStack;
205 secondStack = stack;
206 }
207 break;
208 case TASK_STACK_GOES_ABOVE:
209 case TASK_STACK_GOES_BELOW:
210 mVertical = true;
211 if (position == TASK_STACK_GOES_ABOVE) {
212 mWeight = weight;
213 firstStack = stack;
214 secondStack = mStack;
215 } else {
216 mWeight = 1.0f - weight;
217 firstStack = mStack;
218 secondStack = stack;
219 }
220 break;
Craig Mautnerc00204b2013-03-05 15:02:14 -0800221 }
Craig Mautner967212c2013-04-13 21:10:58 -0700222
Craig Mautner05d29032013-05-03 13:40:13 -0700223 mFirst = new StackBox(mService, mDisplayContent, this);
Craig Mautner967212c2013-04-13 21:10:58 -0700224 firstStack.mStackBox = mFirst;
225 mFirst.mStack = firstStack;
226
Craig Mautner05d29032013-05-03 13:40:13 -0700227 mSecond = new StackBox(mService, mDisplayContent, this);
Craig Mautner967212c2013-04-13 21:10:58 -0700228 secondStack.mStackBox = mSecond;
229 mSecond.mStack = secondStack;
230
231 mStack = null;
232 return stack;
Craig Mautnerc00204b2013-03-05 15:02:14 -0800233 }
234
Craig Mautner00af9fe2013-03-25 09:13:41 -0700235 /** Return the stackId of the first mFirst StackBox with a non-null mStack */
236 int getStackId() {
Craig Mautnerc00204b2013-03-05 15:02:14 -0800237 if (mStack != null) {
Craig Mautner00af9fe2013-03-25 09:13:41 -0700238 return mStack.mStackId;
Craig Mautnerc00204b2013-03-05 15:02:14 -0800239 }
Craig Mautner00af9fe2013-03-25 09:13:41 -0700240 return mFirst.getStackId();
Craig Mautnerc00204b2013-03-05 15:02:14 -0800241 }
242
Craig Mautner00af9fe2013-03-25 09:13:41 -0700243 /** Remove this box and propagate its sibling's content up to their parent.
244 * @return The first stackId of the resulting StackBox. */
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700245 int remove() {
246 if (mStack != null) {
Craig Mautnera9a3fb12013-04-18 10:01:00 -0700247 if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: removing stackId=" + mStack.mStackId);
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700248 mDisplayContent.mStackHistory.remove(mStack);
249 }
250 mDisplayContent.layoutNeeded = true;
251
Craig Mautner9e4f28c2013-04-03 10:53:23 -0700252 if (mParent == null) {
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700253 // This is the top-plane stack.
Craig Mautnera9a3fb12013-04-18 10:01:00 -0700254 if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: removing top plane.");
Craig Mautner9e4f28c2013-04-03 10:53:23 -0700255 mDisplayContent.removeStackBox(this);
256 return HOME_STACK_ID;
257 }
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700258
259 StackBox sibling = isFirstChild() ? mParent.mSecond : mParent.mFirst;
260 StackBox grandparent = mParent.mParent;
Craig Mautnera9a3fb12013-04-18 10:01:00 -0700261 sibling.mParent = grandparent;
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700262 if (grandparent == null) {
263 // mParent is a top-plane stack. Now sibling will be.
Craig Mautnera9a3fb12013-04-18 10:01:00 -0700264 if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: grandparent null");
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700265 mDisplayContent.removeStackBox(mParent);
266 mDisplayContent.addStackBox(sibling, true);
Craig Mautner00af9fe2013-03-25 09:13:41 -0700267 } else {
Craig Mautnera9a3fb12013-04-18 10:01:00 -0700268 if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: grandparent getting sibling");
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700269 if (mParent.isFirstChild()) {
270 grandparent.mFirst = sibling;
271 } else {
272 grandparent.mSecond = sibling;
273 }
Craig Mautner00af9fe2013-03-25 09:13:41 -0700274 }
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700275 return sibling.getStackId();
Craig Mautner00af9fe2013-03-25 09:13:41 -0700276 }
277
Craig Mautner5a449152013-05-24 15:49:29 -0700278 boolean resize(int stackBoxId, float weight) {
279 if (mStackBoxId != stackBoxId) {
280 return mStack == null &&
281 (mFirst.resize(stackBoxId, weight) || mSecond.resize(stackBoxId, weight));
Craig Mautner967212c2013-04-13 21:10:58 -0700282 }
Craig Mautner5a449152013-05-24 15:49:29 -0700283 // Don't change weight on topmost stack.
284 if (mParent != null) {
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700285 mParent.mWeight = isFirstChild() ? weight : 1.0f - weight;
Craig Mautner967212c2013-04-13 21:10:58 -0700286 }
Craig Mautner5a449152013-05-24 15:49:29 -0700287 return true;
Craig Mautnerc00204b2013-03-05 15:02:14 -0800288 }
Craig Mautner00af9fe2013-03-25 09:13:41 -0700289
Craig Mautner967212c2013-04-13 21:10:58 -0700290 /** If this is a terminal StackBox (contains a TaskStack) set the bounds.
291 * @param bounds The rectangle to set the bounds to.
Craig Mautnerd76dcdc2013-06-06 11:26:15 -0700292 * @param underStatusBar True if the StackBox is directly below the Status Bar.
Craig Mautner967212c2013-04-13 21:10:58 -0700293 * @return True if the bounds changed, false otherwise. */
Craig Mautnerd76dcdc2013-06-06 11:26:15 -0700294 boolean setStackBoxSizes(Rect bounds, boolean underStatusBar) {
295 boolean change = false;
296 if (mUnderStatusBar != underStatusBar) {
297 change = true;
298 mUnderStatusBar = underStatusBar;
299 }
Craig Mautner967212c2013-04-13 21:10:58 -0700300 if (mStack != null) {
Craig Mautnerd76dcdc2013-06-06 11:26:15 -0700301 change |= !mBounds.equals(bounds);
Craig Mautnerb3b36ba2013-05-20 13:21:10 -0700302 if (change) {
303 mBounds.set(bounds);
Craig Mautnerd76dcdc2013-06-06 11:26:15 -0700304 mStack.setBounds(bounds, underStatusBar);
Craig Mautnerb3b36ba2013-05-20 13:21:10 -0700305 }
Craig Mautner967212c2013-04-13 21:10:58 -0700306 } else {
307 mTmpRect.set(bounds);
308 if (mVertical) {
309 final int height = bounds.height();
310 int firstHeight = (int)(height * mWeight);
311 mTmpRect.bottom = bounds.top + firstHeight;
Craig Mautnerd76dcdc2013-06-06 11:26:15 -0700312 change |= mFirst.setStackBoxSizes(mTmpRect, underStatusBar);
Craig Mautner967212c2013-04-13 21:10:58 -0700313 mTmpRect.top = mTmpRect.bottom;
314 mTmpRect.bottom = bounds.top + height;
Craig Mautnerd76dcdc2013-06-06 11:26:15 -0700315 change |= mSecond.setStackBoxSizes(mTmpRect, false);
Craig Mautner967212c2013-04-13 21:10:58 -0700316 } else {
317 final int width = bounds.width();
318 int firstWidth = (int)(width * mWeight);
319 mTmpRect.right = bounds.left + firstWidth;
Craig Mautnerd76dcdc2013-06-06 11:26:15 -0700320 change |= mFirst.setStackBoxSizes(mTmpRect, underStatusBar);
Craig Mautner967212c2013-04-13 21:10:58 -0700321 mTmpRect.left = mTmpRect.right;
322 mTmpRect.right = bounds.left + width;
Craig Mautnerd76dcdc2013-06-06 11:26:15 -0700323 change |= mSecond.setStackBoxSizes(mTmpRect, underStatusBar);
Craig Mautner967212c2013-04-13 21:10:58 -0700324 }
325 }
326 return change;
327 }
328
Craig Mautner05d29032013-05-03 13:40:13 -0700329 void resetAnimationBackgroundAnimator() {
330 if (mStack != null) {
331 mStack.resetAnimationBackgroundAnimator();
332 return;
333 }
334 mFirst.resetAnimationBackgroundAnimator();
335 mSecond.resetAnimationBackgroundAnimator();
336 }
337
338 boolean animateDimLayers() {
339 if (mStack != null) {
340 return mStack.animateDimLayers();
341 }
342 boolean result = mFirst.animateDimLayers();
343 result |= mSecond.animateDimLayers();
344 return result;
345 }
346
347 void resetDimming() {
348 if (mStack != null) {
349 mStack.resetDimmingTag();
350 return;
351 }
352 mFirst.resetDimming();
353 mSecond.resetDimming();
354 }
355
356 boolean isDimming() {
357 if (mStack != null) {
358 return mStack.isDimming();
359 }
360 boolean result = mFirst.isDimming();
361 result |= mSecond.isDimming();
362 return result;
363 }
364
365 void stopDimmingIfNeeded() {
366 if (mStack != null) {
367 mStack.stopDimmingIfNeeded();
368 return;
369 }
370 mFirst.stopDimmingIfNeeded();
371 mSecond.stopDimmingIfNeeded();
372 }
373
Craig Mautner00af9fe2013-03-25 09:13:41 -0700374 public void dump(String prefix, PrintWriter pw) {
375 pw.print(prefix); pw.print("mParent="); pw.println(mParent);
Craig Mautner00af9fe2013-03-25 09:13:41 -0700376 pw.print(prefix); pw.print("mBounds="); pw.print(mBounds.toShortString());
Craig Mautner9e4f28c2013-04-03 10:53:23 -0700377 pw.print(" mVertical="); pw.print(mVertical);
378 pw.print(" layoutNeeded="); pw.println(layoutNeeded);
Craig Mautnerde4ef022013-04-07 19:01:33 -0700379 if (mFirst != null) {
Craig Mautner967212c2013-04-13 21:10:58 -0700380 pw.print(prefix); pw.print("mFirst="); pw.println(System.identityHashCode(mFirst));
Craig Mautner00af9fe2013-03-25 09:13:41 -0700381 mFirst.dump(prefix + " ", pw);
Craig Mautner967212c2013-04-13 21:10:58 -0700382 pw.print(prefix); pw.print("mSecond="); pw.println(System.identityHashCode(mSecond));
Craig Mautner00af9fe2013-03-25 09:13:41 -0700383 mSecond.dump(prefix + " ", pw);
Craig Mautnerde4ef022013-04-07 19:01:33 -0700384 } else {
385 pw.print(prefix); pw.print("mStack="); pw.println(mStack);
386 mStack.dump(prefix + " ", pw);
Craig Mautner00af9fe2013-03-25 09:13:41 -0700387 }
388 }
Craig Mautnerde4ef022013-04-07 19:01:33 -0700389
390 @Override
391 public String toString() {
392 if (mStack != null) {
393 return "Box{" + hashCode() + " stack=" + mStack.mStackId + "}";
394 }
Craig Mautner967212c2013-04-13 21:10:58 -0700395 return "Box{" + hashCode() + " parent=" + System.identityHashCode(mParent)
396 + " first=" + System.identityHashCode(mFirst)
397 + " second=" + System.identityHashCode(mSecond) + "}";
Craig Mautnerde4ef022013-04-07 19:01:33 -0700398 }
Craig Mautnerc00204b2013-03-05 15:02:14 -0800399}