Merge "Second pass on Keyguard multi-user switcher" into jb-mr1-dev
This commit is contained in:
@@ -17,9 +17,6 @@
|
||||
-->
|
||||
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate android:fromXDelta="100%p" android:toXDelta="0"
|
||||
android:duration="500"
|
||||
android:interpolator="@interpolator/decelerate_quad" />
|
||||
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
|
||||
android:duration="500"
|
||||
android:interpolator="@interpolator/decelerate_quad" />
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
-->
|
||||
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate android:fromXDelta="0" android:toXDelta="-100%p"
|
||||
android:duration="500"
|
||||
android:interpolator="@interpolator/decelerate_quad" />
|
||||
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
|
||||
android:duration="500"
|
||||
android:interpolator="@interpolator/decelerate_quad" />
|
||||
|
||||
20
core/res/res/drawable/kg_avatar_overlay.xml
Normal file
20
core/res/res/drawable/kg_avatar_overlay.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2012 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true"
|
||||
android:drawable="@drawable/activity_picker_bg_activated" />
|
||||
</selector>
|
||||
@@ -23,9 +23,11 @@
|
||||
android:layout_width="125dp"
|
||||
android:layout_height="125dp"
|
||||
android:background="#550000ff"
|
||||
android:gravity="center_horizontal">
|
||||
android:gravity="center_horizontal"
|
||||
android:foreground="@drawable/kg_avatar_overlay">
|
||||
<ImageView
|
||||
android:id="@+id/keyguard_user_avatar"
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
@@ -19,23 +19,15 @@
|
||||
<com.android.internal.policy.impl.keyguard.KeyguardMultiUserSelectorView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="375dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center">
|
||||
|
||||
<include
|
||||
android:id="@+id/keyguard_active_user"
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="250dp"
|
||||
layout="@layout/keyguard_multi_user_avatar"/>
|
||||
<com.android.internal.policy.impl.keyguard.KeyguardSubdivisionLayout
|
||||
android:id="@+id/keyguard_users_grid"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="300dp"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="125dp"
|
||||
android:layout_height="250dp">
|
||||
<LinearLayout
|
||||
android:id="@+id/keyguard_inactive_users"
|
||||
android:orientation="vertical"
|
||||
layout_width="match_parent"
|
||||
layout_height="wrap_content"/>
|
||||
</ScrollView>
|
||||
</com.android.internal.policy.impl.keyguard.KeyguardMultiUserSelectorView>
|
||||
@@ -1260,10 +1260,9 @@
|
||||
<java-symbol type="id" name="pin_delete_button" />
|
||||
<java-symbol type="id" name="keyguard_user_avatar" />
|
||||
<java-symbol type="id" name="keyguard_user_name" />
|
||||
<java-symbol type="id" name="keyguard_active_user" />
|
||||
<java-symbol type="id" name="keyguard_inactive_users" />
|
||||
<java-symbol type="id" name="keyguard_transport_control" />
|
||||
<java-symbol type="id" name="keyguard_status_view" />
|
||||
<java-symbol type="id" name="keyguard_users_grid" />
|
||||
<java-symbol type="integer" name="config_carDockRotation" />
|
||||
<java-symbol type="integer" name="config_defaultUiModeType" />
|
||||
<java-symbol type="integer" name="config_deskDockRotation" />
|
||||
|
||||
@@ -86,6 +86,11 @@ public class KeyguardHostView extends KeyguardViewBase {
|
||||
void show();
|
||||
}
|
||||
|
||||
/*package*/ interface UserSwitcherCallback {
|
||||
void hideSecurityView(int duration);
|
||||
void showSecurityView();
|
||||
}
|
||||
|
||||
public KeyguardHostView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
@@ -691,11 +696,27 @@ public class KeyguardHostView extends KeyguardViewBase {
|
||||
List<UserInfo> users = mUm.getUsers();
|
||||
|
||||
if (users.size() > 1) {
|
||||
KeyguardWidgetFrame userswitcher = (KeyguardWidgetFrame)
|
||||
KeyguardWidgetFrame userSwitcher = (KeyguardWidgetFrame)
|
||||
LayoutInflater.from(mContext).inflate(R.layout.keyguard_multi_user_selector_widget,
|
||||
mAppWidgetContainer, false);
|
||||
// add the switcher to the left of status view
|
||||
mAppWidgetContainer.addView(userswitcher, getWidgetPosition(R.id.keyguard_status_view));
|
||||
|
||||
// add the switcher in the first position
|
||||
mAppWidgetContainer.addView(userSwitcher, getWidgetPosition(R.id.keyguard_status_view));
|
||||
KeyguardMultiUserSelectorView multiUser = (KeyguardMultiUserSelectorView)
|
||||
userSwitcher.getChildAt(0);
|
||||
|
||||
UserSwitcherCallback callback = new UserSwitcherCallback() {
|
||||
@Override
|
||||
public void hideSecurityView(int duration) {
|
||||
mSecurityViewContainer.animate().alpha(0).setDuration(duration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showSecurityView() {
|
||||
mSecurityViewContainer.setAlpha(1.0f);
|
||||
}
|
||||
};
|
||||
multiUser.setCallback(callback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,16 +16,17 @@
|
||||
|
||||
package com.android.internal.policy.impl.keyguard;
|
||||
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.animation.ValueAnimator.AnimatorUpdateListener;
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.RemoteException;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManagerGlobal;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
@@ -33,11 +34,15 @@ import android.widget.TextView;
|
||||
import com.android.internal.R;
|
||||
|
||||
class KeyguardMultiUserAvatar extends FrameLayout {
|
||||
private static final String TAG = "KeyguardViewHost";
|
||||
|
||||
private ImageView mUserImage;
|
||||
private TextView mUserName;
|
||||
private UserInfo mUserInfo;
|
||||
private static final int INACTIVE_COLOR = 85;
|
||||
private static final int INACTIVE_ALPHA = 195;
|
||||
private static final float ACTIVE_SCALE = 1.1f;
|
||||
private boolean mActive;
|
||||
private boolean mInit = true;
|
||||
private KeyguardMultiUserSelectorView mUserSelector;
|
||||
|
||||
public static KeyguardMultiUserAvatar fromXml(int resId, Context context,
|
||||
@@ -73,17 +78,86 @@ class KeyguardMultiUserAvatar extends FrameLayout {
|
||||
|
||||
mUserImage.setImageDrawable(Drawable.createFromPath(mUserInfo.iconPath));
|
||||
mUserName.setText(mUserInfo.name);
|
||||
setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
try {
|
||||
ActivityManagerNative.getDefault().switchUser(mUserInfo.id);
|
||||
WindowManagerGlobal.getWindowManagerService().lockNow();
|
||||
mUserSelector.init();
|
||||
} catch (RemoteException re) {
|
||||
Log.e(TAG, "Couldn't switch user " + re);
|
||||
setOnClickListener(mUserSelector);
|
||||
setActive(false, false, 0, null);
|
||||
mInit = false;
|
||||
}
|
||||
|
||||
public void setActive(boolean active, boolean animate, int duration, final Runnable onComplete) {
|
||||
if (mActive != active || mInit) {
|
||||
mActive = active;
|
||||
final int finalFilterAlpha = mActive ? 0 : INACTIVE_ALPHA;
|
||||
final int initFilterAlpha = mActive ? INACTIVE_ALPHA : 0;
|
||||
|
||||
final float finalScale = mActive ? ACTIVE_SCALE : 1.0f;
|
||||
final float initScale = mActive ? 1.0f : ACTIVE_SCALE;
|
||||
|
||||
if (active) {
|
||||
KeyguardSubdivisionLayout parent = (KeyguardSubdivisionLayout) getParent();
|
||||
parent.setTopChild(parent.indexOfChild(this));
|
||||
}
|
||||
|
||||
if (animate) {
|
||||
ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
|
||||
va.addUpdateListener(new AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
float r = animation.getAnimatedFraction();
|
||||
float scale = (1 - r) * initScale + r * finalScale;
|
||||
int filterAlpha = (int) ((1 - r) * initFilterAlpha + r * finalFilterAlpha);
|
||||
setScaleX(scale);
|
||||
setScaleY(scale);
|
||||
mUserImage.setColorFilter(Color.argb(filterAlpha, INACTIVE_COLOR,
|
||||
INACTIVE_COLOR, INACTIVE_COLOR));
|
||||
mUserSelector.invalidate();
|
||||
|
||||
}
|
||||
});
|
||||
va.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (onComplete != null) {
|
||||
onComplete.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
va.setDuration(duration);
|
||||
va.start();
|
||||
} else {
|
||||
setScaleX(finalScale);
|
||||
setScaleY(finalScale);
|
||||
mUserImage.setColorFilter(Color.argb(finalFilterAlpha, INACTIVE_COLOR,
|
||||
INACTIVE_COLOR, INACTIVE_COLOR));
|
||||
if (onComplete != null) {
|
||||
post(onComplete);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean mLockDrawableState = false;
|
||||
|
||||
public void lockDrawableState() {
|
||||
mLockDrawableState = true;
|
||||
}
|
||||
|
||||
public void resetDrawableState() {
|
||||
mLockDrawableState = false;
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
refreshDrawableState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void drawableStateChanged() {
|
||||
if (!mLockDrawableState) {
|
||||
super.drawableStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public UserInfo getUserInfo() {
|
||||
return mUserInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,15 +22,26 @@ import android.content.pm.UserInfo;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.LinearLayout;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.WindowManagerGlobal;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.policy.impl.keyguard.KeyguardHostView.UserSwitcherCallback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class KeyguardMultiUserSelectorView extends LinearLayout{
|
||||
private KeyguardMultiUserAvatar mActiveUser;
|
||||
private LinearLayout mInactiveUsers;
|
||||
public class KeyguardMultiUserSelectorView extends FrameLayout implements View.OnClickListener {
|
||||
private static final String TAG = "KeyguardMultiUserSelectorView";
|
||||
|
||||
private KeyguardSubdivisionLayout mUsersGrid;
|
||||
private KeyguardMultiUserAvatar mActiveUserAvatar;
|
||||
private UserSwitcherCallback mCallback;
|
||||
private static final int SWITCH_ANIMATION_DURATION = 150;
|
||||
private static final int FADE_OUT_ANIMATION_DURATION = 100;
|
||||
|
||||
public KeyguardMultiUserSelectorView(Context context) {
|
||||
this(context, null, 0);
|
||||
@@ -48,37 +59,77 @@ public class KeyguardMultiUserSelectorView extends LinearLayout{
|
||||
init();
|
||||
}
|
||||
|
||||
public void setCallback(UserSwitcherCallback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
mActiveUser = (KeyguardMultiUserAvatar) findViewById(R.id.keyguard_active_user);
|
||||
mInactiveUsers = (LinearLayout) findViewById(R.id.keyguard_inactive_users);
|
||||
mUsersGrid = (KeyguardSubdivisionLayout) findViewById(R.id.keyguard_users_grid);
|
||||
mUsersGrid.removeAllViews();
|
||||
setClipChildren(false);
|
||||
setClipToPadding(false);
|
||||
|
||||
mInactiveUsers.removeAllViews();
|
||||
|
||||
UserInfo currentUser;
|
||||
UserInfo activeUser;
|
||||
try {
|
||||
currentUser = ActivityManagerNative.getDefault().getCurrentUser();
|
||||
activeUser = ActivityManagerNative.getDefault().getCurrentUser();
|
||||
} catch (RemoteException re) {
|
||||
currentUser = null;
|
||||
activeUser = null;
|
||||
}
|
||||
|
||||
UserManager mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
|
||||
ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUm.getUsers());
|
||||
Collections.sort(users, mOrderAddedComparator);
|
||||
|
||||
for (UserInfo user: users) {
|
||||
if (user.id == currentUser.id) {
|
||||
setActiveUser(user);
|
||||
} else {
|
||||
createAndAddInactiveUser(user);
|
||||
KeyguardMultiUserAvatar uv = createAndAddUser(user);
|
||||
if (user.id == activeUser.id) {
|
||||
mActiveUserAvatar = uv;
|
||||
}
|
||||
}
|
||||
mActiveUserAvatar.setActive(true, false, 0, null);
|
||||
}
|
||||
|
||||
private void setActiveUser(UserInfo user) {
|
||||
mActiveUser.setup(user, this);
|
||||
}
|
||||
Comparator<UserInfo> mOrderAddedComparator = new Comparator<UserInfo>() {
|
||||
@Override
|
||||
public int compare(UserInfo lhs, UserInfo rhs) {
|
||||
return (lhs.serialNumber - rhs.serialNumber);
|
||||
}
|
||||
};
|
||||
|
||||
private void createAndAddInactiveUser(UserInfo user) {
|
||||
private KeyguardMultiUserAvatar createAndAddUser(UserInfo user) {
|
||||
KeyguardMultiUserAvatar uv = KeyguardMultiUserAvatar.fromXml(
|
||||
R.layout.keyguard_multi_user_avatar, mContext, this, user);
|
||||
mInactiveUsers.addView(uv);
|
||||
mUsersGrid.addView(uv);
|
||||
return uv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (!(v instanceof KeyguardMultiUserAvatar)) return;
|
||||
final KeyguardMultiUserAvatar avatar = (KeyguardMultiUserAvatar) v;
|
||||
if (mActiveUserAvatar == avatar) {
|
||||
// They clicked the active user, no need to do anything
|
||||
return;
|
||||
} else {
|
||||
// Reset the previously active user to appear inactive
|
||||
avatar.lockDrawableState();
|
||||
mCallback.hideSecurityView(FADE_OUT_ANIMATION_DURATION);
|
||||
mActiveUserAvatar.setActive(false, true, SWITCH_ANIMATION_DURATION, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ActivityManagerNative.getDefault().switchUser(avatar.getUserInfo().id);
|
||||
WindowManagerGlobal.getWindowManagerService().lockNow();
|
||||
// Set the new active user, and make it appear active
|
||||
avatar.resetDrawableState();
|
||||
mCallback.showSecurityView();
|
||||
mActiveUserAvatar = avatar;
|
||||
mActiveUserAvatar.setActive(true, false, 0, null);
|
||||
} catch (RemoteException re) {
|
||||
Log.e(TAG, "Couldn't switch user " + re);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.internal.policy.impl.keyguard;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A layout that arranges its children into a special type of grid.
|
||||
*/
|
||||
public class KeyguardSubdivisionLayout extends ViewGroup {
|
||||
ArrayList<BiTree> mCells = new ArrayList<BiTree>();
|
||||
int mNumChildren = -1;
|
||||
int mWidth = -1;
|
||||
int mHeight = -1;
|
||||
int mTopChild = 0;
|
||||
|
||||
public KeyguardSubdivisionLayout(Context context) {
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public KeyguardSubdivisionLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public KeyguardSubdivisionLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
setClipChildren(false);
|
||||
setClipToPadding(false);
|
||||
setChildrenDrawingOrderEnabled(true);
|
||||
}
|
||||
|
||||
private class BiTree {
|
||||
Rect rect;
|
||||
BiTree left;
|
||||
BiTree right;
|
||||
int nodeDepth;
|
||||
ArrayList<BiTree> leafs;
|
||||
|
||||
public BiTree(Rect r) {
|
||||
rect = r;
|
||||
}
|
||||
|
||||
public BiTree() {
|
||||
}
|
||||
|
||||
boolean isLeaf() {
|
||||
return (left == null) && (right == null);
|
||||
}
|
||||
|
||||
int depth() {
|
||||
if (left != null && right != null) {
|
||||
return Math.max(left.depth(), right.depth()) + 1;
|
||||
} else if (left != null) {
|
||||
return left.depth() + 1;
|
||||
} else if (right != null) {
|
||||
return right.depth() + 1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int numLeafs() {
|
||||
if (left != null && right != null) {
|
||||
return left.numLeafs() + right.numLeafs();
|
||||
} else if (left != null) {
|
||||
return left.numLeafs();
|
||||
} else if (right != null) {
|
||||
return right.numLeafs();
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
BiTree getNextNodeToBranch() {
|
||||
if (leafs == null) {
|
||||
leafs = new ArrayList<BiTree>();
|
||||
}
|
||||
leafs.clear();
|
||||
getLeafs(leafs, 1);
|
||||
|
||||
// We find the first leaf who's depth is not
|
||||
double r = log2(leafs.size());
|
||||
if (Math.ceil(r) == Math.floor(r)) {
|
||||
return leafs.get(leafs.size() - 1);
|
||||
}
|
||||
|
||||
int treeDepth = depth();
|
||||
for (int i = leafs.size() - 1; i >= 0; i--) {
|
||||
BiTree n = leafs.get(i);
|
||||
if (n.nodeDepth < treeDepth) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Gets leafs in left to right order
|
||||
void getLeafs(ArrayList<BiTree> leafs, int depth) {
|
||||
if (isLeaf()) {
|
||||
this.nodeDepth = depth;
|
||||
leafs.add(this);
|
||||
} else {
|
||||
if (left != null) {
|
||||
left.getLeafs(leafs, depth + 1);
|
||||
}
|
||||
if (right != null) {
|
||||
right.getLeafs(leafs, depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double log2(double d) {
|
||||
return Math.log(d) / Math.log(2);
|
||||
}
|
||||
|
||||
private void addCell(BiTree tree) {
|
||||
BiTree branch = tree.getNextNodeToBranch();
|
||||
Rect r = branch.rect;
|
||||
branch.left = new BiTree();
|
||||
branch.right = new BiTree();
|
||||
int newDepth = tree.depth();
|
||||
|
||||
// For each level of the tree, we alternate between horizontal and vertical division
|
||||
if (newDepth % 2 == 0) {
|
||||
// Divide the cell vertically
|
||||
branch.left.rect = new Rect(r.left, r.top, r.right, r.top + r.height() / 2);
|
||||
branch.right.rect = new Rect(r.left, r.top + r.height() / 2, r.right, r.bottom);
|
||||
} else {
|
||||
// Divide the cell horizontally
|
||||
branch.left.rect = new Rect(r.left, r.top, r.left + r.width() / 2, r.bottom);
|
||||
branch.right.rect = new Rect(r.left + r.width() / 2, r.top, r.right, r.bottom);
|
||||
}
|
||||
}
|
||||
|
||||
private void constructGrid(int width, int height, int numChildren) {
|
||||
mCells.clear();
|
||||
BiTree root = new BiTree(new Rect(0, 0, width, height));
|
||||
|
||||
// We add nodes systematically until the number of leafs matches the number of children
|
||||
while (root.numLeafs() < numChildren) {
|
||||
addCell(root);
|
||||
}
|
||||
|
||||
// Spit out the final list of cells
|
||||
root.getLeafs(mCells, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int height = MeasureSpec.getSize(heightMeasureSpec);
|
||||
int childCount = getChildCount();
|
||||
|
||||
if (mNumChildren != childCount || width != getMeasuredWidth() ||
|
||||
height != getMeasuredHeight()) {
|
||||
constructGrid(width, height, childCount);
|
||||
}
|
||||
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
Rect rect = mCells.get(i).rect;
|
||||
child.measure(MeasureSpec.makeMeasureSpec(rect.width(), MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(rect.height(), MeasureSpec.EXACTLY));
|
||||
}
|
||||
setMeasuredDimension(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
int childCount = getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
Rect rect = mCells.get(i).rect;
|
||||
child.layout(rect.left, rect.top, rect.right, rect.bottom);
|
||||
}
|
||||
}
|
||||
|
||||
public void setTopChild(int top) {
|
||||
mTopChild = top;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
protected int getChildDrawingOrder(int childCount, int i) {
|
||||
int ret = i;
|
||||
if (i == childCount - 1) {
|
||||
ret = mTopChild;
|
||||
} else if (i >= mTopChild){
|
||||
ret = i + 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user