Merge change Ia895aa7d into eclair

* changes:
  Fix for 2209086:  Initial pass at new SlidingTab widget and integration into LockScreen.
This commit is contained in:
Android (Google) Code Review
2009-11-11 14:02:00 -08:00
65 changed files with 1202 additions and 0 deletions

View File

@@ -0,0 +1,626 @@
/*
* Copyright (C) 2009 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.widget;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.ImageView.ScaleType;
import com.android.internal.R;
/**
* A special widget containing two Sliders and a threshold for each. Moving either slider beyond
* the threshold will cause the registered OnTriggerListener.onTrigger() to be called with
* {@link OnTriggerListener#LEFT_HANDLE} or {@link OnTriggerListener#RIGHT_HANDLE} to be called.
*
*/
public class SlidingTab extends ViewGroup {
private static final String LOG_TAG = "SlidingTab";
private static final boolean DBG = false;
private static final int HORIZONTAL = 0; // as defined in attrs.xml
private static final int VERTICAL = 1;
private static final int MSG_ANIMATE = 100;
// TODO: Make these configurable
private static final float TARGET_ZONE = 2.0f / 3.0f;
private static final long VIBRATE_SHORT = 30;
private static final long VIBRATE_LONG = 40;
private OnTriggerListener mOnTriggerListener;
private int mGrabbedState = OnTriggerListener.NO_HANDLE;
private boolean mTriggered = false;
private Vibrator mVibrator;
private float mDensity; // used to scale dimensions for bitmaps.
private final SlidingTabHandler mHandler = new SlidingTabHandler();
/**
* Either {@link #HORIZONTAL} or {@link #VERTICAL}.
*/
private int mOrientation;
private Slider mLeftSlider;
private Slider mRightSlider;
private Slider mCurrentSlider;
private boolean mTracking;
private float mTargetZone;
private Slider mOtherSlider;
private boolean mAnimating;
/**
* Interface definition for a callback to be invoked when a tab is triggered
* by moving it beyond a target zone.
*/
public interface OnTriggerListener {
/**
* The interface was triggered because the user let go of the handle without reaching the
* target zone.
*/
public static final int NO_HANDLE = 0;
/**
* The interface was triggered because the user grabbed the left handle and moved it past
* the target zone.
*/
public static final int LEFT_HANDLE = 1;
/**
* The interface was triggered because the user grabbed the right handle and moved it past
* the target zone.
*/
public static final int RIGHT_HANDLE = 2;
/**
* Called when the user moves a handle beyond the target zone.
*
* @param v The view that was triggered.
* @param whichHandle Which "dial handle" the user grabbed,
* either {@link #LEFT_HANDLE}, {@link #RIGHT_HANDLE}.
*/
void onTrigger(View v, int whichHandle);
/**
* Called when the "grabbed state" changes (i.e. when the user either grabs or releases
* one of the handles.)
*
* @param v the view that was triggered
* @param grabbedState the new state: {@link #NO_HANDLE}, {@link #LEFT_HANDLE},
* or {@link #RIGHT_HANDLE}.
*/
void onGrabbedStateChange(View v, int grabbedState);
}
/**
* Simple container class for all things pertinent to a slider.
* A slider consists of 3 Views:
*
* {@link #tab} is the tab shown on the screen in the default state.
* {@link #text} is the view revealed as the user slides the tab out.
* {@link #target} is the target the user must drag the slider past to trigger the slider.
*
*/
private static class Slider {
/**
* Tab alignment - determines which side the tab should be drawn on
*/
public static final int ALIGN_LEFT = 0;
public static final int ALIGN_RIGHT = 1;
public static final int ALIGN_TOP = 2;
public static final int ALIGN_BOTTOM = 3;
/**
* States for the view.
*/
private static final int STATE_NORMAL = 0;
private static final int STATE_PRESSED = 1;
private static final int STATE_ACTIVE = 2;
private final ImageView tab;
private final TextView text;
private final ImageView target;
/**
* Constructor
*
* @param parent the container view of this one
* @param tabId drawable for the tab
* @param barId drawable for the bar
* @param targetId drawable for the target
*/
Slider(ViewGroup parent, int tabId, int barId, int targetId) {
// Create tab
tab = new ImageView(parent.getContext());
tab.setBackgroundResource(tabId);
tab.setScaleType(ScaleType.CENTER);
tab.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
// Create hint TextView
text = new TextView(parent.getContext());
text.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.FILL_PARENT));
text.setBackgroundResource(barId);
text.setTextAppearance(parent.getContext(), R.style.TextAppearance_SlidingTabNormal);
// hint.setSingleLine(); // Hmm.. this causes the text to disappear off-screen
// Create target
target = new ImageView(parent.getContext());
target.setImageResource(targetId);
target.setScaleType(ScaleType.CENTER);
target.setLayoutParams(
new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
target.setVisibility(View.INVISIBLE);
parent.addView(target); // this needs to be first - relies on painter's algorithm
parent.addView(tab);
parent.addView(text);
}
void setIcon(int iconId) {
tab.setImageResource(iconId);
}
void setTabBackgroundResource(int tabId) {
tab.setBackgroundResource(tabId);
}
void setBarBackgroundResource(int barId) {
text.setBackgroundResource(barId);
}
void setHintText(int resId) {
// TODO: Text should be blank if widget is vertical
text.setText(resId);
}
void hide() {
// TODO: Animate off the screen
text.setVisibility(View.INVISIBLE);
tab.setVisibility(View.INVISIBLE);
target.setVisibility(View.INVISIBLE);
}
void setState(int state) {
text.setPressed(state == STATE_PRESSED);
tab.setPressed(state == STATE_PRESSED);
if (state == STATE_ACTIVE) {
final int[] activeState = new int[] {com.android.internal.R.attr.state_active};
if (text.getBackground().isStateful()) {
text.getBackground().setState(activeState);
}
if (tab.getBackground().isStateful()) {
tab.getBackground().setState(activeState);
}
text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabActive);
} else {
text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabNormal);
}
}
void showTarget() {
target.setVisibility(View.VISIBLE);
}
void reset() {
setState(STATE_NORMAL);
text.setVisibility(View.VISIBLE);
text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabNormal);
tab.setVisibility(View.VISIBLE);
target.setVisibility(View.INVISIBLE);
}
void setTarget(int targetId) {
target.setImageResource(targetId);
}
/**
* Layout the given widgets within the parent.
*
* @param l the parent's left border
* @param t the parent's top border
* @param r the parent's right border
* @param b the parent's bottom border
* @param alignment which side to align the widget to
*/
void layout(int l, int t, int r, int b, int alignment) {
final int handleWidth = tab.getBackground().getIntrinsicWidth();
final int handleHeight = tab.getBackground().getIntrinsicHeight();
final int targetWidth = target.getDrawable().getIntrinsicWidth();
final int targetHeight = target.getDrawable().getIntrinsicHeight();
final int parentWidth = r - l;
final int parentHeight = b - t;
final int leftTarget = (int) (TARGET_ZONE * parentWidth) - targetWidth + handleWidth / 2;
final int rightTarget = (int) ((1.0f - TARGET_ZONE) * parentWidth) - handleWidth / 2;
final int left = (parentWidth - handleWidth) / 2;
final int right = left + handleWidth;
if (alignment == ALIGN_LEFT || alignment == ALIGN_RIGHT) {
// horizontal
final int targetTop = (parentHeight - targetHeight) / 2;
final int targetBottom = targetTop + targetHeight;
final int top = (parentHeight - handleHeight) / 2;
final int bottom = (parentHeight + handleHeight) / 2;
if (alignment == ALIGN_LEFT) {
tab.layout(0, top, handleWidth, bottom);
text.layout(0 - parentWidth, top, 0, bottom);
text.setGravity(Gravity.RIGHT);
target.layout(leftTarget, targetTop, leftTarget + targetWidth, targetBottom);
} else {
tab.layout(parentWidth - handleWidth, top, parentWidth, bottom);
text.layout(parentWidth, top, parentWidth + parentWidth, bottom);
target.layout(rightTarget, targetTop, rightTarget + targetWidth, targetBottom);
text.setGravity(Gravity.TOP);
}
} else {
// vertical
final int targetLeft = (parentWidth - targetWidth) / 2;
final int targetRight = (parentWidth + targetWidth) / 2;
final int top = (int) (TARGET_ZONE * parentHeight) + handleHeight / 2 - targetHeight;
final int bottom = (int) ((1.0f - TARGET_ZONE) * parentHeight) - handleHeight / 2;
if (alignment == ALIGN_TOP) {
tab.layout(left, 0, right, handleHeight);
text.layout(left, 0 - parentHeight, right, 0);
target.layout(targetLeft, top, targetRight, top + targetHeight);
} else {
tab.layout(left, parentHeight - handleHeight, right, parentHeight);
text.layout(left, parentHeight, right, parentHeight + parentHeight);
target.layout(targetLeft, bottom, targetRight, bottom + targetHeight);
}
}
}
public int getTabWidth() {
return tab.getDrawable().getIntrinsicWidth();
}
public int getTabHeight() {
return tab.getDrawable().getIntrinsicHeight();
}
}
public SlidingTab(Context context) {
this(context, null);
}
/**
* Constructor used when this widget is created from a layout file.
*/
public SlidingTab(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlidingTab);
mOrientation = a.getInt(R.styleable.SlidingTab_orientation, HORIZONTAL);
a.recycle();
Resources r = getResources();
mDensity = r.getDisplayMetrics().density;
if (DBG) log("- Density: " + mDensity);
mLeftSlider = new Slider(this,
R.drawable.jog_tab_left_generic,
R.drawable.jog_tab_bar_left_generic,
R.drawable.jog_tab_target_gray);
mRightSlider = new Slider(this,
R.drawable.jog_tab_right_generic,
R.drawable.jog_tab_bar_right_generic,
R.drawable.jog_tab_target_gray);
// setBackgroundColor(0x80808080);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
throw new RuntimeException(LOG_TAG + " cannot have UNSPECIFIED dimensions");
}
final int leftTabWidth = (int) (mDensity * mLeftSlider.getTabWidth() + 0.5f);
final int rightTabWidth = (int) (mDensity * mRightSlider.getTabWidth() + 0.5f);
final int leftTabHeight = (int) (mDensity * mLeftSlider.getTabHeight() + 0.5f);
final int rightTabHeight = (int) (mDensity * mRightSlider.getTabHeight() + 0.5f);
final int width;
final int height;
if (isHorizontal()) {
width = Math.max(widthSpecSize, leftTabWidth + rightTabWidth);
height = Math.max(leftTabHeight, rightTabHeight);
} else {
width = Math.max(leftTabWidth, rightTabHeight);
height = Math.max(heightSpecSize, leftTabHeight + rightTabHeight);
}
setMeasuredDimension(width, height);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
final int action = event.getAction();
final float x = event.getX();
final float y = event.getY();
final Rect frame = new Rect();
if (mAnimating) {
return false;
}
View leftHandle = mLeftSlider.tab;
leftHandle.getHitRect(frame);
boolean leftHit = frame.contains((int) x, (int) y);
View rightHandle = mRightSlider.tab;
rightHandle.getHitRect(frame);
boolean rightHit = frame.contains((int)x, (int) y);
if (!mTracking && !(leftHit || rightHit)) {
return false;
}
switch (action) {
case MotionEvent.ACTION_DOWN: {
mTracking = true;
mTriggered = false;
vibrate(VIBRATE_SHORT);
if (leftHit) {
mCurrentSlider = mLeftSlider;
mOtherSlider = mRightSlider;
mTargetZone = isHorizontal() ? TARGET_ZONE : 1.0f - TARGET_ZONE;
setGrabbedState(OnTriggerListener.LEFT_HANDLE);
} else {
mCurrentSlider = mRightSlider;
mOtherSlider = mLeftSlider;
mTargetZone = isHorizontal() ? 1.0f - TARGET_ZONE : TARGET_ZONE;
setGrabbedState(OnTriggerListener.RIGHT_HANDLE);
}
mCurrentSlider.setState(Slider.STATE_PRESSED);
mCurrentSlider.showTarget();
mOtherSlider.hide();
break;
}
}
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mTracking) {
final int action = event.getAction();
final float x = event.getX();
final float y = event.getY();
final View handle = mCurrentSlider.tab;
switch (action) {
case MotionEvent.ACTION_MOVE:
moveHandle(x, y);
float position = isHorizontal() ? x : y;
float target = mTargetZone * (isHorizontal() ? getWidth() : getHeight());
boolean targetZoneReached;
if (isHorizontal()) {
targetZoneReached = mCurrentSlider == mLeftSlider ?
position > target : position < target;
} else {
targetZoneReached = mCurrentSlider == mLeftSlider ?
position < target : position > target;
}
if (!mTriggered && targetZoneReached) {
mTriggered = true;
mTracking = false;
mCurrentSlider.setState(Slider.STATE_ACTIVE);
dispatchTriggerEvent(mCurrentSlider == mLeftSlider ?
OnTriggerListener.LEFT_HANDLE : OnTriggerListener.RIGHT_HANDLE);
// TODO: This is a place holder for the real animation. It just holds
// the screen for 500ms.
mAnimating = true;
mHandler.postDelayed(new Runnable() {
public void run() {
resetView();
mAnimating = false;
}
}, 500);
}
if (isHorizontal() && (y <= handle.getBottom() && y >= handle.getTop()) ||
!isHorizontal() && (x >= handle.getLeft() && x <= handle.getRight()) ) {
break;
}
// Intentionally fall through - we're outside tracking rectangle
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mTracking = false;
mTriggered = false;
resetView();
setGrabbedState(OnTriggerListener.NO_HANDLE);
break;
}
}
return mTracking || super.onTouchEvent(event);
}
private boolean isHorizontal() {
return mOrientation == HORIZONTAL;
}
private void resetView() {
mLeftSlider.reset();
mRightSlider.reset();
onLayout(true, getLeft(), getTop(), getLeft() + getWidth(), getTop() + getHeight());
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (!changed) return;
// Center the widgets in the view
mLeftSlider.layout(l, t, r, b, isHorizontal() ? Slider.ALIGN_LEFT : Slider.ALIGN_BOTTOM);
mRightSlider.layout(l, t, r, b, isHorizontal() ? Slider.ALIGN_RIGHT : Slider.ALIGN_TOP);
invalidate(); // TODO: be more conservative about what we're invalidating
}
private void moveHandle(float x, float y) {
final View handle = mCurrentSlider.tab;
final View content = mCurrentSlider.text;
if (isHorizontal()) {
int deltaX = (int) x - handle.getLeft() - (handle.getWidth() / 2);
handle.offsetLeftAndRight(deltaX);
content.offsetLeftAndRight(deltaX);
} else {
int deltaY = (int) y - handle.getTop() - (handle.getHeight() / 2);
handle.offsetTopAndBottom(deltaY);
content.offsetTopAndBottom(deltaY);
}
invalidate(); // TODO: be more conservative about what we're invalidating
}
/**
* Sets the left handle icon to a given resource.
*
* The resource should refer to a Drawable object, or use 0 to remove
* the icon.
*
* @param iconId the resource ID of the icon drawable
* @param targetId the resource of the target drawable
* @param barId the resource of the bar drawable (stateful)
* @param tabId the resource of the
*/
public void setLeftTabResources(int iconId, int targetId, int barId, int tabId) {
mLeftSlider.setIcon(iconId);
mLeftSlider.setTarget(targetId);
mLeftSlider.setBarBackgroundResource(barId);
mLeftSlider.setTabBackgroundResource(tabId);
}
/**
* Sets the left handle hint text to a given resource string.
*
* @param resId
*/
public void setLeftHintText(int resId) {
mLeftSlider.setHintText(resId);
}
/**
* Sets the right handle icon to a given resource.
*
* The resource should refer to a Drawable object, or use 0 to remove
* the icon.
*
* @param iconId the resource ID of the icon drawable
* @param targetId the resource of the target drawable
* @param barId the resource of the bar drawable (stateful)
* @param tabId the resource of the
*/
public void setRightTabResources(int iconId, int targetId, int barId, int tabId) {
mRightSlider.setIcon(iconId);
mRightSlider.setTarget(targetId);
mRightSlider.setBarBackgroundResource(barId);
mRightSlider.setTabBackgroundResource(tabId);
}
/**
* Sets the left handle hint text to a given resource string.
*
* @param resId
*/
public void setRightHintText(int resId) {
mRightSlider.setHintText(resId);
}
/**
* Triggers haptic feedback.
*/
private synchronized void vibrate(long duration) {
if (mVibrator == null) {
mVibrator = (android.os.Vibrator)
getContext().getSystemService(Context.VIBRATOR_SERVICE);
}
mVibrator.vibrate(duration);
}
/**
* Registers a callback to be invoked when the user triggers an event.
*
* @param listener the OnDialTriggerListener to attach to this view
*/
public void setOnTriggerListener(OnTriggerListener listener) {
mOnTriggerListener = listener;
}
/**
* Dispatches a trigger event to listener. Ignored if a listener is not set.
* @param whichHandle the handle that triggered the event.
*/
private void dispatchTriggerEvent(int whichHandle) {
vibrate(VIBRATE_LONG);
if (mOnTriggerListener != null) {
mOnTriggerListener.onTrigger(this, whichHandle);
}
}
/**
* Sets the current grabbed state, and dispatches a grabbed state change
* event to our listener.
*/
private void setGrabbedState(int newState) {
if (newState != mGrabbedState) {
mGrabbedState = newState;
if (mOnTriggerListener != null) {
mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState);
}
}
}
private class SlidingTabHandler extends Handler {
public void handleMessage(Message m) {
switch (m.what) {
case MSG_ANIMATE:
doAnimation();
break;
}
}
}
private void doAnimation() {
if (mAnimating) {
}
}
private void log(String msg) {
Log.d(LOG_TAG, msg);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 931 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 959 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 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.
-->
<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/jog_tab_bar_pressed" />
<item android:state_enabled="true"
android:drawable="@drawable/jog_tab_bar_normal" />
<item android:state_active="true"
android:drawable="@drawable/jog_tab_bar_confirm_gray" />
</selector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 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.
-->
<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/jog_tab_bar_pressed" />
<item android:state_enabled="true"
android:drawable="@drawable/jog_tab_bar_normal" />
<item android:state_active="true"
android:drawable="@drawable/jog_tab_bar_confirm_green" />
</selector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 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.
-->
<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/jog_tab_bar_pressed" />
<item android:state_enabled="true"
android:drawable="@drawable/jog_tab_bar_normal" />
<item android:state_active="true"
android:drawable="@drawable/jog_tab_bar_confirm_gray" />
</selector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 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.
-->
<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/jog_tab_bar_pressed" />
<item android:state_enabled="true"
android:drawable="@drawable/jog_tab_bar_normal" />
<item android:state_active="true"
android:drawable="@drawable/jog_tab_bar_confirm_gray" />
</selector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 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.
-->
<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/jog_tab_bar_pressed" />
<item android:state_enabled="true"
android:drawable="@drawable/jog_tab_bar_normal" />
<item android:state_active="true"
android:drawable="@drawable/jog_tab_bar_confirm_yellow" />
</selector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 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.
-->
<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/jog_tab_left_pressed" />
<item android:state_enabled="true"
android:drawable="@drawable/jog_tab_left_normal" />
<item android:state_active="true"
android:drawable="@drawable/jog_tab_left_confirm_gray" />
</selector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 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.
-->
<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/jog_tab_left_pressed" />
<item android:state_enabled="true"
android:drawable="@drawable/jog_tab_left_normal" />
<item android:state_active="true"
android:drawable="@drawable/jog_tab_left_confirm_green" />
</selector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 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.
-->
<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/jog_tab_right_pressed" />
<item android:state_enabled="true"
android:drawable="@drawable/jog_tab_right_normal" />
<item android:state_active="true"
android:drawable="@drawable/jog_tab_right_confirm_gray" />
</selector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 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.
-->
<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/jog_tab_right_pressed" />
<item android:state_enabled="true"
android:drawable="@drawable/jog_tab_right_normal" />
<item android:state_active="true"
android:drawable="@drawable/jog_tab_right_confirm_gray" />
</selector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 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.
-->
<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/jog_tab_right_pressed" />
<item android:state_enabled="true"
android:drawable="@drawable/jog_tab_right_normal" />
<item android:state_active="true"
android:drawable="@drawable/jog_tab_right_confirm_yellow" />
</selector>

View File

@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 2009, 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.
*/
-->
<!-- This is the general lock screen which shows information about the
state of the device, as well as instructions on how to get past it
depending on the state of the device. It is the same for landscape
and portrait.-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/root">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#70000000"
android:gravity="center_horizontal">
<TextView
android:id="@+id/carrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginTop="20dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
/>
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/carrier"
android:layout_marginTop="25dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="55sp"
/>
<TextView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/time"
android:layout_marginTop="-12dip"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
<View
android:id="@+id/divider"
android:layout_width="fill_parent"
android:layout_height="1dip"
android:layout_marginTop="10dip"
android:layout_below="@id/date"
android:background="@android:drawable/divider_horizontal_dark"
/>
<TextView
android:id="@+id/status1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/divider"
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
android:drawablePadding="4dip"
/>
<TextView
android:id="@+id/status2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/status1"
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
android:drawablePadding="4dip"
/>
<TextView
android:id="@+id/screenLocked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/status2"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
android:gravity="center"
android:layout_marginTop="12dip"
/>
<com.android.internal.widget.SlidingTab
android:id="@+id/tab_selector"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="50dip"
/>
<!-- emergency call button shown when sim is missing or PUKd -->
<Button
android:id="@+id/emergencyCallButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/screenLocked"
android:layout_marginTop="24dip"
android:drawableLeft="@drawable/ic_emergency"
android:drawablePadding="8dip"
/>
</RelativeLayout>
</FrameLayout>

View File

@@ -0,0 +1,130 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 2009, 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.
*/
-->
<!-- This is the general lock screen which shows information about the
state of the device, as well as instructions on how to get past it
depending on the state of the device.-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:background="#70000000"
android:id="@+id/root">
<!-- left side -->
<RelativeLayout
android:layout_width="0dip"
android:layout_height="fill_parent"
android:layout_weight="1.0"
android:gravity="center_horizontal">
<TextView
android:id="@+id/carrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginTop="20dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
/>
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/carrier"
android:layout_marginTop="25dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="55sp"
/>
<TextView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/time"
android:layout_marginTop="-12dip"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
<View
android:id="@+id/divider"
android:layout_width="fill_parent"
android:layout_height="1dip"
android:layout_marginTop="10dip"
android:layout_below="@id/date"
android:background="@android:drawable/divider_horizontal_dark"
/>
<TextView
android:id="@+id/status1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/divider"
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
android:drawablePadding="4dip"
/>
<TextView
android:id="@+id/status2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/status1"
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
android:drawablePadding="4dip"
/>
<TextView
android:id="@+id/screenLocked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/status2"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
android:gravity="center"
android:layout_marginTop="12dip"
/>
<!-- emergency call button shown when sim is missing or PUKd -->
<Button
android:id="@+id/emergencyCallButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/screenLocked"
android:layout_marginTop="24dip"
android:drawableLeft="@drawable/ic_emergency"
android:drawablePadding="8dip"
/>
</RelativeLayout>
<!-- right side -->
<com.android.internal.widget.SlidingTab
android:id="@+id/tab_selector"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginBottom="50dip"
/>
</LinearLayout>

View File

@@ -3559,4 +3559,14 @@
<attr name="detailSocialSummary" format="boolean" />
</declare-styleable>
<!-- =============================== -->
<!-- TabSelector class attributes -->
<!-- =============================== -->
<eat-comment />
<declare-styleable name="SlidingTab">
<!-- Use "horizontal" for a row, "vertical" for a column. The default is horizontal. -->
<attr name="orientation" />
</declare-styleable>
</resources>

View File

@@ -84,6 +84,10 @@
<color name="search_url_text_selected">@android:color/black</color>
<color name="search_url_text_pressed">@android:color/black</color>
<color name="search_widget_corpus_item_background">@android:color/lighter_gray</color>
<!-- SlidingTab -->
<color name="sliding_tab_text_color_active">@android:color/black</color>
<color name="sliding_tab_text_color_shadow">@android:color/black</color>
</resources>

View File

@@ -1434,6 +1434,10 @@
<!-- Displayed in a progress dialog while a username and password are being checked. -->
<string name="lockscreen_glogin_checking_password">Checking...</string>
<!-- Displayed on lock screen's left tab - unlock -->
<string name="lockscreen_unlock_label">Unlock</string>
<!-- Displayed on lock screen's right tab - mute/unmute -->
<string name="lockscreen_mute_unmute_label">Sound</string>
<!-- A format string for 12-hour time of day, just the hour, not the minute, with lower-case "am" or "pm" (example: "3pm"). -->
<string name="hour_ampm">"<xliff:g id="hour" example="3">%-l</xliff:g><xliff:g id="ampm" example="pm">%P</xliff:g>"</string>

View File

@@ -676,6 +676,25 @@
<style name="TextAppearance.Widget.TextView.SpinnerItem">
<item name="android:textColor">@android:color/primary_text_light_disable_only</item>
</style>
<!-- @hide -->
<style name="TextAppearance.SlidingTabNormal"
parent="@android:attr/textAppearanceMedium">
<item name="android:textColor">?android:attr/textColorTertiary</item>
<item name="android:textSize">28sp</item>
<item name="android:shadowColor">@android:color/sliding_tab_text_color_shadow</item>
<item name="android:shadowDx">0.0</item>
<item name="android:shadowDy">1.0</item>
<item name="android:shadowRadius">5.0</item>
</style>
<!-- @hide -->
<style name="TextAppearance.SlidingTabActive"
parent="@android:attr/textAppearanceMedium">
<item name="android:textColor">@android:color/sliding_tab_text_color_active</item>
<item name="android:textSize">28sp</item>
</style>
<!-- @hide -->
<style name="TextAppearance.SearchResult">