diff options
37 files changed, 1410 insertions, 868 deletions
diff --git a/api/current.xml b/api/current.xml index d682155..0cf46eb 100644 --- a/api/current.xml +++ b/api/current.xml @@ -1905,7 +1905,7 @@ type="int" transient="false" volatile="false" - value="16843550" + value="16843552" static="true" final="true" deprecated="not deprecated" @@ -1916,7 +1916,7 @@ type="int" transient="false" volatile="false" - value="16843549" + value="16843551" static="true" final="true" deprecated="not deprecated" @@ -1927,7 +1927,7 @@ type="int" transient="false" volatile="false" - value="16843551" + value="16843553" static="true" final="true" deprecated="not deprecated" @@ -3804,6 +3804,17 @@ visibility="public" > </field> +<field name="enterFadeDuration" + type="int" + transient="false" + volatile="false" + value="16843549" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="entries" type="int" transient="false" @@ -3848,6 +3859,17 @@ visibility="public" > </field> +<field name="exitFadeDuration" + type="int" + transient="false" + volatile="false" + value="16843550" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="expandableListPreferredChildIndicatorLeft" type="int" transient="false" @@ -9308,7 +9330,7 @@ type="int" transient="false" volatile="false" - value="16843553" + value="16843555" static="true" final="true" deprecated="not deprecated" @@ -9319,7 +9341,7 @@ type="int" transient="false" volatile="false" - value="16843552" + value="16843554" static="true" final="true" deprecated="not deprecated" @@ -19503,6 +19525,17 @@ <parameter name="index" type="int"> </parameter> </method> +<method name="getTabCount" + return="int" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getTitle" return="java.lang.CharSequence" abstract="true" @@ -28300,6 +28333,17 @@ visibility="public" > </method> +<method name="disallowAddToBackStack" + return="android.app.FragmentTransaction" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="hide" return="android.app.FragmentTransaction" abstract="true" @@ -28313,6 +28357,17 @@ <parameter name="fragment" type="android.app.Fragment"> </parameter> </method> +<method name="isAddToBackStackAllowed" + return="boolean" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="isEmpty" return="boolean" abstract="true" @@ -83932,6 +83987,17 @@ visibility="public" > </method> +<method name="jumpToCurrentState" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="mutate" return="android.graphics.drawable.Drawable" abstract="false" @@ -84421,6 +84487,32 @@ <parameter name="state" type="android.graphics.drawable.DrawableContainer.DrawableContainerState"> </parameter> </method> +<method name="setEnterFadeDuration" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="ms" type="int"> +</parameter> +</method> +<method name="setExitFadeDuration" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="ms" type="int"> +</parameter> +</method> <method name="unscheduleDrawable" return="void" abstract="false" @@ -84568,6 +84660,28 @@ visibility="public" > </method> +<method name="getEnterFadeDuration" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getExitFadeDuration" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getOpacity" return="int" abstract="false" @@ -84629,6 +84743,32 @@ <parameter name="constant" type="boolean"> </parameter> </method> +<method name="setEnterFadeDuration" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<parameter name="duration" type="int"> +</parameter> +</method> +<method name="setExitFadeDuration" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<parameter name="duration" type="int"> +</parameter> +</method> <method name="setVariablePadding" return="void" abstract="false" @@ -190423,6 +190563,17 @@ <parameter name="newSize" type="int"> </parameter> </method> +<field name="NOTHING" + type="int[]" + transient="false" + volatile="false" + value="null" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="WILD_CARD" type="int[]" transient="false" @@ -203765,6 +203916,17 @@ visibility="public" > </method> +<method name="jumpDrawablesToCurrentState" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="layout" return="void" abstract="false" diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java index 39754b0..1945b05 100644 --- a/core/java/android/animation/PropertyValuesHolder.java +++ b/core/java/android/animation/PropertyValuesHolder.java @@ -665,6 +665,11 @@ public class PropertyValuesHolder implements Cloneable { public IntPropertyValuesHolder(String propertyName, int... values) { super(propertyName); setIntValues(values); + } + + @Override + public void setIntValues(int... values) { + super.setIntValues(values); mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet; } @@ -722,6 +727,11 @@ public class PropertyValuesHolder implements Cloneable { public FloatPropertyValuesHolder(String propertyName, float... values) { super(propertyName); setFloatValues(values); + } + + @Override + public void setFloatValues(float... values) { + super.setFloatValues(values); mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet; } diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java index e185624..a57b54a 100644 --- a/core/java/android/app/ActionBar.java +++ b/core/java/android/app/ActionBar.java @@ -478,6 +478,12 @@ public abstract class ActionBar { public abstract Tab getTabAt(int index); /** + * Returns the number of tabs currently registered with the action bar. + * @return Tab count + */ + public abstract int getTabCount(); + + /** * Retrieve the current height of the ActionBar. * * @return The ActionBar's height @@ -626,7 +632,8 @@ public abstract class ActionBar { * @param tab The tab that was selected * @param ft A {@link FragmentTransaction} for queuing fragment operations to execute * during a tab switch. The previous tab's unselect and this tab's select will be - * executed in a single transaction. + * executed in a single transaction. This FragmentTransaction does not support + * being added to the back stack. */ public void onTabSelected(Tab tab, FragmentTransaction ft); @@ -636,7 +643,8 @@ public abstract class ActionBar { * @param tab The tab that was unselected * @param ft A {@link FragmentTransaction} for queuing fragment operations to execute * during a tab switch. This tab's unselect and the newly selected tab's select - * will be executed in a single transaction. + * will be executed in a single transaction. This FragmentTransaction does not + * support being added to the back stack. */ public void onTabUnselected(Tab tab, FragmentTransaction ft); @@ -646,7 +654,8 @@ public abstract class ActionBar { * * @param tab The tab that was reselected. * @param ft A {@link FragmentTransaction} for queuing fragment operations to execute - * once this method returns. + * once this method returns. This FragmentTransaction does not support + * being added to the back stack. */ public void onTabReselected(Tab tab, FragmentTransaction ft); } diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java index e6cc0f9..c75777d 100644 --- a/core/java/android/app/BackStackRecord.java +++ b/core/java/android/app/BackStackRecord.java @@ -186,6 +186,7 @@ final class BackStackRecord implements FragmentTransaction, int mTransition; int mTransitionStyle; boolean mAddToBackStack; + boolean mAllowAddToBackStack = true; String mName; boolean mCommitted; int mIndex; @@ -346,11 +347,28 @@ final class BackStackRecord implements FragmentTransaction, } public FragmentTransaction addToBackStack(String name) { + if (!mAllowAddToBackStack) { + throw new IllegalStateException( + "This FragmentTransaction is not allowed to be added to the back stack."); + } mAddToBackStack = true; mName = name; return this; } + public boolean isAddToBackStackAllowed() { + return mAllowAddToBackStack; + } + + public FragmentTransaction disallowAddToBackStack() { + if (mAddToBackStack) { + throw new IllegalStateException( + "This transaction is already being added to the back stack"); + } + mAllowAddToBackStack = false; + return this; + } + public FragmentTransaction setBreadCrumbTitle(int res) { mBreadCrumbTitleRes = res; mBreadCrumbTitleText = null; diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java index b00476b..19da763 100644 --- a/core/java/android/app/FragmentTransaction.java +++ b/core/java/android/app/FragmentTransaction.java @@ -144,6 +144,22 @@ public interface FragmentTransaction { public FragmentTransaction addToBackStack(String name); /** + * Returns true if this FragmentTransaction is allowed to be added to the back + * stack. If this method would return false, {@link #addToBackStack(String)} + * will throw {@link IllegalStateException}. + * + * @return True if {@link #addToBackStack(String)} is permitted on this transaction. + */ + public boolean isAddToBackStackAllowed(); + + /** + * Disallow calls to {@link #addToBackStack(String)}. Any future calls to + * addToBackStack will throw {@link IllegalStateException}. If addToBackStack + * has already been called, this method will throw IllegalStateException. + */ + public FragmentTransaction disallowAddToBackStack(); + + /** * Set the full title to show as a bread crumb when this transaction * is on the back stack, as used by {@link FragmentBreadCrumbs}. * diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl index 7743ceb..cd08e33 100644 --- a/core/java/android/nfc/INfcAdapter.aidl +++ b/core/java/android/nfc/INfcAdapter.aidl @@ -39,8 +39,6 @@ interface INfcAdapter // NfcAdapter-class related methods boolean isEnabled(); - NdefMessage localGet(); - void localSet(in NdefMessage message); void openTagConnection(in Tag tag); // Non-public methods diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index cf80faf..88b6ea4 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -301,48 +301,6 @@ public final class NfcAdapter { } /** - * Set the NDEF Message that this NFC adapter should appear as to Tag - * readers. - * <p> - * Any Tag reader can read the contents of the local tag when it is in - * proximity, without any further user confirmation. - * <p> - * The implementation of this method must either - * <ul> - * <li>act as a passive tag containing this NDEF message - * <li>provide the NDEF message on over LLCP to peer NFC adapters - * </ul> - * The NDEF message is preserved across reboot. - * <p>Requires {@link android.Manifest.permission#NFC} permission. - * - * @param message NDEF message to make public - * @hide - */ - public void setLocalNdefMessage(NdefMessage message) { - try { - mService.localSet(message); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - } - } - - /** - * Get the NDEF Message that this adapter appears as to Tag readers. - * <p>Requires {@link android.Manifest.permission#NFC} permission. - * - * @return NDEF Message that is publicly readable - * @hide - */ - public NdefMessage getLocalNdefMessage() { - try { - return mService.localGet(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - return null; - } - } - - /** * Create a raw tag connection to the default Target * <p>Requires {@link android.Manifest.permission#NFC} permission. * @hide diff --git a/core/java/android/util/StateSet.java b/core/java/android/util/StateSet.java index f3d8159..21d8e45 100644 --- a/core/java/android/util/StateSet.java +++ b/core/java/android/util/StateSet.java @@ -38,6 +38,7 @@ import com.android.internal.R; public class StateSet { public static final int[] WILD_CARD = new int[0]; + public static final int[] NOTHING = new int[] { 0 }; /** * Return whether the stateSetOrSpec is matched by all StateSets. diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 7276044..340678d 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -8620,6 +8620,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} + * on all Drawable objects associated with this view. + */ + public void jumpDrawablesToCurrentState() { + if (mBGDrawable != null) { + mBGDrawable.jumpToCurrentState(); + } + } + + /** * Sets the background color for this view. * @param color the color of the background */ @@ -8627,6 +8637,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility public void setBackgroundColor(int color) { if (mBGDrawable instanceof ColorDrawable) { ((ColorDrawable) mBGDrawable).setColor(color); + invalidate(); } else { setBackgroundDrawable(new ColorDrawable(color)); } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 4e90ecd..7629673 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -36,6 +36,7 @@ import android.util.AttributeSet; import android.util.Log; import android.util.LongSparseArray; import android.util.SparseBooleanArray; +import android.util.StateSet; import android.view.ActionMode; import android.view.Gravity; import android.view.HapticFeedbackConstants; @@ -254,6 +255,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te Drawable mSelector; /** + * Set to true if we would like to have the selector showing itself. + * We still need to draw and position it even if this is false. + */ + boolean mSelectorShowing; + + /** + * The current position of the selector in the list. + */ + int mSelectorPosition = INVALID_POSITION; + + /** * Defines the selector's location and dimension at drawing time */ Rect mSelectorRect = new Rect(); @@ -1324,6 +1336,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te setSelectedPositionInt(INVALID_POSITION); // Do this before setting mNeedSync since setNextSelectedPosition looks at mNeedSync setNextSelectedPositionInt(INVALID_POSITION); + mSelectorPosition = INVALID_POSITION; mNeedSync = true; mSyncRowId = ss.firstId; mSyncPosition = ss.position; @@ -1416,6 +1429,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te setSelectedPositionInt(INVALID_POSITION); setNextSelectedPositionInt(INVALID_POSITION); mSelectedTop = 0; + mSelectorShowing = false; + mSelectorPosition = INVALID_POSITION; mSelectorRect.setEmpty(); invalidate(); } @@ -1708,7 +1723,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } if (child != scrapView) { - mRecycler.addScrapView(scrapView); + mRecycler.addScrapView(scrapView, position); if (mCacheColorHint != 0) { child.setDrawingCacheBackgroundColor(mCacheColorHint); } @@ -1734,7 +1749,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te return child; } - void positionSelector(View sel) { + void positionSelector(int position, View sel) { + if (position != INVALID_POSITION) { + mSelectorPosition = position; + } + final Rect selectorRect = mSelectorRect; selectorRect.set(sel.getLeft(), sel.getTop(), sel.getRight(), sel.getBottom()); positionSelector(selectorRect.left, selectorRect.top, selectorRect.right, @@ -1743,7 +1762,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final boolean isChildViewEnabled = mIsChildViewEnabled; if (sel.isEnabled() != isChildViewEnabled) { mIsChildViewEnabled = !isChildViewEnabled; - refreshDrawableState(); + if (mSelectorShowing) { + refreshDrawableState(); + } } } @@ -1822,7 +1843,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } private void drawSelector(Canvas canvas) { - if (shouldShowSelector() && mSelectorRect != null && !mSelectorRect.isEmpty()) { + if (!mSelectorRect.isEmpty()) { final Drawable selector = mSelector; selector.setBounds(mSelectorRect); selector.draw(canvas); @@ -1866,7 +1887,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mSelectionRightPadding = padding.right; mSelectionBottomPadding = padding.bottom; sel.setCallback(this); - sel.setState(getDrawableState()); + updateSelectorState(); } /** @@ -1891,7 +1912,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te Drawable selector = mSelector; Rect selectorRect = mSelectorRect; if (selector != null && (isFocused() || touchModeDrawsInPressedState()) - && selectorRect != null && !selectorRect.isEmpty()) { + && !selectorRect.isEmpty()) { final View v = getChildAt(mSelectedPosition - mFirstPosition); @@ -1926,12 +1947,20 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mScrollDown = down; } + void updateSelectorState() { + if (mSelector != null) { + if (shouldShowSelector()) { + mSelector.setState(getDrawableState()); + } else { + mSelector.setState(StateSet.NOTHING); + } + } + } + @Override protected void drawableStateChanged() { super.drawableStateChanged(); - if (mSelector != null) { - mSelector.setState(getDrawableState()); - } + updateSelectorState(); } @Override @@ -2141,7 +2170,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } else { mTouchMode = TOUCH_MODE_DONE_WAITING; } - } } } @@ -2316,10 +2344,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mLayoutMode = LAYOUT_NORMAL; if (!mDataChanged) { - layoutChildren(); child.setPressed(true); - positionSelector(child); setPressed(true); + layoutChildren(); + positionSelector(mMotionPosition, child); final int longPressTimeout = ViewConfiguration.getLongPressTimeout(); final boolean longClickable = isLongClickable(); @@ -2566,7 +2594,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te setSelectedPositionInt(mMotionPosition); layoutChildren(); child.setPressed(true); - positionSelector(child); + positionSelector(mMotionPosition, child); setPressed(true); if (mSelector != null) { Drawable d = mSelector.getCurrent(); @@ -2576,16 +2604,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } postDelayed(new Runnable() { public void run() { + mTouchMode = TOUCH_MODE_REST; child.setPressed(false); setPressed(false); if (!mDataChanged) { post(performClick); } - mTouchMode = TOUCH_MODE_REST; } }, ViewConfiguration.getPressedStateDuration()); } else { mTouchMode = TOUCH_MODE_REST; + updateSelectorState(); } return true; } else if (!mDataChanged && mAdapter.isEnabled(motionPosition)) { @@ -2593,6 +2622,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } mTouchMode = TOUCH_MODE_REST; + updateSelectorState(); break; case TOUCH_MODE_SCROLL: final int childCount = getChildCount(); @@ -3507,7 +3537,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te count++; int position = firstPosition + i; if (position >= headerViewsCount && position < footerViewsStart) { - mRecycler.addScrapView(child); + mRecycler.addScrapView(child, position); if (ViewDebug.TRACE_RECYCLER) { ViewDebug.trace(child, @@ -3528,7 +3558,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te count++; int position = firstPosition + i; if (position >= headerViewsCount && position < footerViewsStart) { - mRecycler.addScrapView(child); + mRecycler.addScrapView(child, position); if (ViewDebug.TRACE_RECYCLER) { ViewDebug.trace(child, @@ -3563,8 +3593,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (!inTouchMode && mSelectedPosition != INVALID_POSITION) { final int childIndex = mSelectedPosition - mFirstPosition; if (childIndex >= 0 && childIndex < getChildCount()) { - positionSelector(getChildAt(childIndex)); + positionSelector(mSelectedPosition, getChildAt(childIndex)); + } + } else if (mSelectorPosition != INVALID_POSITION) { + final int childIndex = mSelectorPosition - mFirstPosition; + if (childIndex >= 0 && childIndex < getChildCount()) { + positionSelector(INVALID_POSITION, getChildAt(childIndex)); } + } else { + mSelectorRect.setEmpty(); } mBlockLayoutRequests = false; @@ -3616,7 +3653,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te setSelectedPositionInt(INVALID_POSITION); setNextSelectedPositionInt(INVALID_POSITION); mSelectedTop = 0; - mSelectorRect.setEmpty(); + mSelectorShowing = false; } } @@ -3876,6 +3913,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mNextSelectedPosition = INVALID_POSITION; mNextSelectedRowId = INVALID_ROW_ID; mNeedSync = false; + mSelectorPosition = INVALID_POSITION; checkSelectionChanged(); } @@ -4562,6 +4600,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te @ViewDebug.ExportedProperty(category = "list") boolean forceAdd; + /** + * The position the view was removed from when pulled out of the + * scrap heap. + * @hide + */ + int scrappedFromPosition; + public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); } @@ -4741,23 +4786,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * @return A view from the ScrapViews collection. These are unordered. */ View getScrapView(int position) { - ArrayList<View> scrapViews; if (mViewTypeCount == 1) { - scrapViews = mCurrentScrap; - int size = scrapViews.size(); - if (size > 0) { - return scrapViews.remove(size - 1); - } else { - return null; - } + return retrieveFromScrap(mCurrentScrap, position); } else { int whichScrap = mAdapter.getItemViewType(position); if (whichScrap >= 0 && whichScrap < mScrapViews.length) { - scrapViews = mScrapViews[whichScrap]; - int size = scrapViews.size(); - if (size > 0) { - return scrapViews.remove(size - 1); - } + return retrieveFromScrap(mScrapViews[whichScrap], position); } } return null; @@ -4768,7 +4802,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * * @param scrap The view to add */ - void addScrapView(View scrap) { + void addScrapView(View scrap, int position) { AbsListView.LayoutParams lp = (AbsListView.LayoutParams) scrap.getLayoutParams(); if (lp == null) { return; @@ -4784,6 +4818,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te return; } + lp.scrappedFromPosition = position; + if (mViewTypeCount == 1) { scrap.dispatchStartTemporaryDetach(); mCurrentScrap.add(scrap); @@ -4810,7 +4846,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te for (int i = count - 1; i >= 0; i--) { final View victim = activeViews[i]; if (victim != null) { - int whichScrap = ((AbsListView.LayoutParams) victim.getLayoutParams()).viewType; + final AbsListView.LayoutParams lp + = (AbsListView.LayoutParams) victim.getLayoutParams(); + int whichScrap = lp.viewType; activeViews[i] = null; @@ -4826,6 +4864,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te scrapViews = mScrapViews[whichScrap]; } victim.dispatchStartTemporaryDetach(); + lp.scrappedFromPosition = mFirstActivePosition + i; scrapViews.add(victim); if (hasListener) { @@ -4911,4 +4950,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } } + + static View retrieveFromScrap(ArrayList<View> scrapViews, int position) { + int size = scrapViews.size(); + if (size > 0) { + // See if we still have a view for this position. + for (int i=0; i<size; i++) { + View view = scrapViews.get(i); + if (((AbsListView.LayoutParams)view.getLayoutParams()) + .scrappedFromPosition == position) { + scrapViews.remove(i); + return view; + } + } + return scrapViews.remove(size - 1); + } else { + return null; + } + } } diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index f5afb94..f16efbd 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -18,7 +18,6 @@ package android.widget; import android.content.Context; import android.database.DataSetObserver; -import android.os.Handler; import android.os.Parcelable; import android.os.SystemClock; import android.util.AttributeSet; diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index 46c7d33..936a97d 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -1009,7 +1009,7 @@ public class GridView extends AbsListView { childHeight = child.getMeasuredHeight(); if (mRecycler.shouldRecycleViewType(p.viewType)) { - mRecycler.addScrapView(child); + mRecycler.addScrapView(child, -1); } } @@ -1148,7 +1148,7 @@ public class GridView extends AbsListView { if (dataChanged) { for (int i = 0; i < childCount; i++) { - recycleBin.addScrapView(getChildAt(i)); + recycleBin.addScrapView(getChildAt(i), firstPosition+i); } } else { recycleBin.fillActiveViews(childCount, firstPosition); @@ -1215,11 +1215,11 @@ public class GridView extends AbsListView { recycleBin.scrapActiveViews(); if (sel != null) { - positionSelector(sel); + positionSelector(INVALID_POSITION, sel); mSelectedTop = sel.getTop(); } else if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_SCROLL) { View child = getChildAt(mMotionPosition - mFirstPosition); - if (child != null) positionSelector(child); + if (child != null) positionSelector(mMotionPosition, child); } else { mSelectedTop = 0; mSelectorRect.setEmpty(); @@ -1391,6 +1391,11 @@ public class GridView extends AbsListView { if (mCachingStarted) { child.setDrawingCacheEnabled(true); } + + if (recycled && (((AbsListView.LayoutParams)child.getLayoutParams()).scrappedFromPosition) + != position) { + child.jumpDrawablesToCurrentState(); + } } /** diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index b5e103f..e0119e9 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -581,7 +581,7 @@ public class ListView extends AbsListView { final boolean scroll = scrollYDelta != 0; if (scroll) { scrollListItemsBy(-scrollYDelta); - positionSelector(child); + positionSelector(INVALID_POSITION, child); mSelectedTop = child.getTop(); invalidate(); } @@ -1086,7 +1086,7 @@ public class ListView extends AbsListView { if (recycleOnMeasure() && mRecycler.shouldRecycleViewType( ((LayoutParams) child.getLayoutParams()).viewType)) { - mRecycler.addScrapView(child); + mRecycler.addScrapView(child, -1); } } @@ -1203,7 +1203,7 @@ public class ListView extends AbsListView { // Recycle the view before we possibly return from the method if (recyle && recycleBin.shouldRecycleViewType( ((LayoutParams) child.getLayoutParams()).viewType)) { - recycleBin.addScrapView(child); + recycleBin.addScrapView(child, -1); } returnedHeight += child.getMeasuredHeight(); @@ -1507,7 +1507,7 @@ public class ListView extends AbsListView { // already cached in mHeaderViews; if (dataChanged) { for (int i = 0; i < childCount; i++) { - recycleBin.addScrapView(getChildAt(i)); + recycleBin.addScrapView(getChildAt(i), firstPosition+i); if (ViewDebug.TRACE_RECYCLER) { ViewDebug.trace(getChildAt(i), ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP, index, i); @@ -1610,19 +1610,19 @@ public class ListView extends AbsListView { if (focused != null) { focused.clearFocus(); } - positionSelector(sel); + positionSelector(INVALID_POSITION, sel); } else { sel.setSelected(false); mSelectorRect.setEmpty(); } } else { - positionSelector(sel); + positionSelector(INVALID_POSITION, sel); } mSelectedTop = sel.getTop(); } else { if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_SCROLL) { View child = getChildAt(mMotionPosition - mFirstPosition); - if (child != null) positionSelector(child); + if (child != null) positionSelector(mMotionPosition, child); } else { mSelectedTop = 0; mSelectorRect.setEmpty(); @@ -1703,7 +1703,7 @@ public class ListView extends AbsListView { if (!mDataChanged) { - // Try to use an exsiting view for this position + // Try to use an existing view for this position child = mRecycler.getActiveView(position); if (child != null) { if (ViewDebug.TRACE_RECYCLER) { @@ -1820,6 +1820,11 @@ public class ListView extends AbsListView { if (mCachingStarted && !child.isDrawingCacheEnabled()) { child.setDrawingCacheEnabled(true); } + + if (recycled && (((AbsListView.LayoutParams)child.getLayoutParams()).scrappedFromPosition) + != position) { + child.jumpDrawablesToCurrentState(); + } } @Override @@ -2288,6 +2293,7 @@ public class ListView extends AbsListView { } View selectedView = getSelectedView(); + int selectedPos = mSelectedPosition; int nextSelectedPosition = lookForSelectablePositionOnScreen(direction); int amountToScroll = amountToScroll(direction, nextSelectedPosition); @@ -2305,6 +2311,7 @@ public class ListView extends AbsListView { setSelectedPositionInt(nextSelectedPosition); setNextSelectedPositionInt(nextSelectedPosition); selectedView = getSelectedView(); + selectedPos = nextSelectedPosition; if (mItemsCanFocus && focusResult == null) { // there was no new view found to take focus, make sure we // don't leave focus with the old selection @@ -2345,7 +2352,7 @@ public class ListView extends AbsListView { if (needToRedraw) { if (selectedView != null) { - positionSelector(selectedView); + positionSelector(selectedPos, selectedView); mSelectedTop = selectedView.getTop(); } if (!awakenScrollBars()) { @@ -2841,7 +2848,7 @@ public class ListView extends AbsListView { AbsListView.LayoutParams layoutParams = (LayoutParams) first.getLayoutParams(); if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) { detachViewFromParent(first); - recycleBin.addScrapView(first); + recycleBin.addScrapView(first, mFirstPosition); } else { removeViewInLayout(first); } @@ -2872,7 +2879,7 @@ public class ListView extends AbsListView { AbsListView.LayoutParams layoutParams = (LayoutParams) last.getLayoutParams(); if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) { detachViewFromParent(last); - recycleBin.addScrapView(last); + recycleBin.addScrapView(last, mFirstPosition+lastIndex); } else { removeViewInLayout(last); } diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java index 1d612e2..7cf369f 100644 --- a/core/java/com/android/internal/app/ActionBarImpl.java +++ b/core/java/com/android/internal/app/ActionBarImpl.java @@ -65,12 +65,15 @@ public class ActionBarImpl extends ActionBar { private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>(); private TabImpl mSelectedTab; + private int mSavedTabPosition = INVALID_POSITION; private ActionMode mActionMode; private static final int CONTEXT_DISPLAY_NORMAL = 0; private static final int CONTEXT_DISPLAY_SPLIT = 1; + private static final int INVALID_POSITION = -1; + private int mContextDisplayMode; private boolean mClosingContext; @@ -183,6 +186,8 @@ public class ActionBarImpl extends ActionBar { selectTab(null); } mTabs.clear(); + mActionView.removeAllTabs(); + mSavedTabPosition = INVALID_POSITION; } public void setTitle(CharSequence title) { @@ -310,6 +315,8 @@ public class ActionBarImpl extends ActionBar { @Override public void removeTabAt(int position) { + int selectedTabPosition = mSelectedTab != null + ? mSelectedTab.getPosition() : mSavedTabPosition; mActionView.removeTabAt(position); mTabs.remove(position); @@ -318,7 +325,9 @@ public class ActionBarImpl extends ActionBar { mTabs.get(i).setPosition(i); } - selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1))); + if (selectedTabPosition == position) { + selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1))); + } } @Override @@ -333,7 +342,13 @@ public class ActionBarImpl extends ActionBar { @Override public void selectTab(Tab tab) { - final FragmentTransaction trans = mActivity.getFragmentManager().openTransaction(); + if (getNavigationMode() != NAVIGATION_MODE_TABS) { + mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION; + return; + } + + final FragmentTransaction trans = mActivity.getFragmentManager().openTransaction() + .disallowAddToBackStack(); if (mSelectedTab == tab) { if (mSelectedTab != null) { @@ -623,12 +638,52 @@ public class ActionBarImpl extends ActionBar { } @Override + public int getTabCount() { + return mTabs.size(); + } + + @Override public void setNavigationMode(int mode) { + final int oldMode = mActionView.getNavigationMode(); + switch (oldMode) { + case NAVIGATION_MODE_TABS: + mSavedTabPosition = getSelectedNavigationIndex(); + selectTab(null); + break; + } mActionView.setNavigationMode(mode); + switch (mode) { + case NAVIGATION_MODE_TABS: + if (mSavedTabPosition != INVALID_POSITION) { + setSelectedNavigationItem(mSavedTabPosition); + mSavedTabPosition = INVALID_POSITION; + } + break; + } } @Override public Tab getTabAt(int index) { return mTabs.get(index); } + + /** + * This fragment is added when we're keeping a back stack in a tab switch + * transaction. We use it to change the selected tab in the action bar view + * when we back out. + */ + private class SwitchSelectedTabViewFragment extends Fragment { + private int mSelectedTabIndex; + + public SwitchSelectedTabViewFragment(int oldSelectedTab) { + mSelectedTabIndex = oldSelectedTab; + } + + @Override + public void onDetach() { + if (mSelectedTabIndex >= 0 && mSelectedTabIndex < getTabCount()) { + mActionView.setTabSelected(mSelectedTabIndex); + } + } + } } diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java index 95d6dd3..8ead9c8 100644 --- a/core/java/com/android/internal/widget/ActionBarView.java +++ b/core/java/com/android/internal/widget/ActionBarView.java @@ -487,6 +487,12 @@ public class ActionBarView extends ViewGroup { } } + public void removeAllTabs() { + if (mTabLayout != null) { + mTabLayout.removeAllViews(); + } + } + @Override protected LayoutParams generateDefaultLayoutParams() { // Used by custom nav views if they don't supply layout params. Everything else diff --git a/core/java/com/android/internal/widget/WaveView.java b/core/java/com/android/internal/widget/WaveView.java index f4ee7ee..f91d3d6 100644 --- a/core/java/com/android/internal/widget/WaveView.java +++ b/core/java/com/android/internal/widget/WaveView.java @@ -53,8 +53,10 @@ public class WaveView extends View implements ValueAnimator.AnimatorUpdateListen private static final int STATE_UNLOCK_SUCCESS = 5; // Animation properties. - private static final long DURATION = 500; // duration of transitional animations - private static final long FINAL_DELAY = 1300; // delay for final animations + private static final long DURATION = 300; // duration of transitional animations + private static final long FINAL_DURATION = 200; // duration of final animations when unlocking + private static final long RING_DELAY = 1300; // when to start fading animated rings + private static final long FINAL_DELAY = 200; // delay for unlock success animation private static final long SHORT_DELAY = 100; // for starting one animation after another. private static final long WAVE_DURATION = 2000; // amount of time for way to expand/decay private static final long RESET_TIMEOUT = 3000; // elapsed time of inactivity before we reset @@ -299,11 +301,11 @@ public class WaveView extends View implements ValueAnimator.AnimatorUpdateListen // x:ringX, y:ringY, scaleX: .1, scaleY: .1, ease:Quint.easeOut}); DrawableHolder wave = mLightWaves.get(n); long delay = 1000L*(6 + n - mCurrentWave)/10L; - wave.addAnimTo(DURATION, delay, "x", ringX, true); - wave.addAnimTo(DURATION, delay, "y", ringY, true); - wave.addAnimTo(DURATION, delay, "scaleX", 0.1f, true); - wave.addAnimTo(DURATION, delay, "scaleY", 0.1f, true); - wave.addAnimTo(DURATION, delay, "alpha", 0.0f, true); + wave.addAnimTo(FINAL_DURATION, delay, "x", ringX, true); + wave.addAnimTo(FINAL_DURATION, delay, "y", ringY, true); + wave.addAnimTo(FINAL_DURATION, delay, "scaleX", 0.1f, true); + wave.addAnimTo(FINAL_DURATION, delay, "scaleY", 0.1f, true); + wave.addAnimTo(FINAL_DURATION, delay, "alpha", 0.0f, true); } for (int i = 0; i < mLightWaves.size(); i++) { mLightWaves.get(i).startAnimations(this); @@ -311,14 +313,14 @@ public class WaveView extends View implements ValueAnimator.AnimatorUpdateListen //TweenMax.to(unlockRing, .5, {x:ringX, y: ringY, scaleX: .1, scaleY: .1, // alpha: 0, ease: Quint.easeOut }); - mUnlockRing.addAnimTo(DURATION, 0, "x", ringX, false); - mUnlockRing.addAnimTo(DURATION, 0, "y", ringY, false); - mUnlockRing.addAnimTo(DURATION, 0, "scaleX", 0.1f, false); - mUnlockRing.addAnimTo(DURATION, 0, "scaleY", 0.1f, false); - mUnlockRing.addAnimTo(DURATION, 0, "alpha", 0.0f, false); + mUnlockRing.addAnimTo(FINAL_DURATION, 0, "x", ringX, false); + mUnlockRing.addAnimTo(FINAL_DURATION, 0, "y", ringY, false); + mUnlockRing.addAnimTo(FINAL_DURATION, 0, "scaleX", 0.1f, false); + mUnlockRing.addAnimTo(FINAL_DURATION, 0, "scaleY", 0.1f, false); + mUnlockRing.addAnimTo(FINAL_DURATION, 0, "alpha", 0.0f, false); //TweenMax.to(unlockRing, .5, { delay: 1.3, alpha: 0 , ease: Quint.easeOut }); - mUnlockRing.addAnimTo(DURATION, FINAL_DELAY, "alpha", 0.0f, false); + mUnlockRing.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false); //TweenMax.to(unlockDefault, 0, { x:ringX, y: ringY, scaleX: .1, scaleY: .1, // alpha: 0 , overwrite: true }); @@ -332,27 +334,27 @@ public class WaveView extends View implements ValueAnimator.AnimatorUpdateListen //TweenMax.to(unlockDefault, .5, { x:ringX, y: ringY, scaleX: 1, scaleY: 1, // alpha: 1 , ease: Quint.easeOut , overwrite: true }); - mUnlockDefault.addAnimTo(DURATION, 0, "x", ringX, true); - mUnlockDefault.addAnimTo(DURATION, 0, "y", ringY, true); - mUnlockDefault.addAnimTo(DURATION, 0, "scaleX", 1.0f, true); - mUnlockDefault.addAnimTo(DURATION, 0, "scaleY", 1.0f, true); - mUnlockDefault.addAnimTo(DURATION, 0, "alpha", 1.0f, true); + mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "x", ringX, true); + mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "y", ringY, true); + mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "scaleX", 1.0f, true); + mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "scaleY", 1.0f, true); + mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "alpha", 1.0f, true); //TweenMax.to(unlockDefault, .5, { delay: 1.3, scaleX: 3, scaleY: 3, // alpha: 1, ease: Quint.easeOut }); - mUnlockDefault.addAnimTo(DURATION, FINAL_DELAY, "scaleX", 3.0f, false); - mUnlockDefault.addAnimTo(DURATION, FINAL_DELAY, "scaleY", 3.0f, false); - mUnlockDefault.addAnimTo(DURATION, FINAL_DELAY, "alpha", 1.0f, false); + mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleX", 3.0f, false); + mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleY", 3.0f, false); + mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false); //TweenMax.to(unlockHalo, .5, { x:ringX, y: ringY , ease: Back.easeOut }); - mUnlockHalo.addAnimTo(DURATION, 0, "x", ringX, false); - mUnlockHalo.addAnimTo(DURATION, 0, "y", ringY, false); + mUnlockHalo.addAnimTo(FINAL_DURATION, 0, "x", ringX, false); + mUnlockHalo.addAnimTo(FINAL_DURATION, 0, "y", ringY, false); //TweenMax.to(unlockHalo, .5, { delay: 1.3, scaleX: 3, scaleY: 3, // alpha: 1, ease: Quint.easeOut }); - mUnlockHalo.addAnimTo(DURATION, FINAL_DELAY, "scaleX", 3.0f, false); - mUnlockHalo.addAnimTo(DURATION, FINAL_DELAY, "scaleY", 3.0f, false); - mUnlockHalo.addAnimTo(DURATION, FINAL_DELAY, "alpha", 1.0f, false); + mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleX", 3.0f, false); + mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleY", 3.0f, false); + mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false); removeCallbacks(mLockTimerActions); @@ -437,7 +439,7 @@ public class WaveView extends View implements ValueAnimator.AnimatorUpdateListen //TweenMax.to(this["lightWave"+currentWave], 1, { delay: 1.3 // , alpha: 0 , ease:Quint.easeOut}); - wave.addAnimTo(1000, FINAL_DELAY, "alpha", 0.0f, false); + wave.addAnimTo(1000, RING_DELAY, "alpha", 0.0f, false); wave.startAnimations(WaveView.this); mCurrentWave = (mCurrentWave+1) % mWaveCount; diff --git a/core/res/res/drawable/activated_background.xml b/core/res/res/drawable/activated_background.xml index d92fba1..1047e5b 100644 --- a/core/res/res/drawable/activated_background.xml +++ b/core/res/res/drawable/activated_background.xml @@ -14,7 +14,8 @@ limitations under the License. --> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + android:exitFadeDuration="@android:integer/config_mediumAnimTime"> <item android:state_activated="true" android:drawable="@android:drawable/list_selector_background_selected" /> <item android:drawable="@color/transparent" /> </selector> diff --git a/core/res/res/drawable/activated_background_holo_dark.xml b/core/res/res/drawable/activated_background_holo_dark.xml index febf2c4..a29bcb9 100644 --- a/core/res/res/drawable/activated_background_holo_dark.xml +++ b/core/res/res/drawable/activated_background_holo_dark.xml @@ -14,7 +14,8 @@ limitations under the License. --> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + android:exitFadeDuration="@android:integer/config_mediumAnimTime"> <item android:state_activated="true" android:drawable="@android:drawable/list_activated_holo" /> <item android:drawable="@color/transparent" /> </selector> diff --git a/core/res/res/drawable/activated_background_holo_light.xml b/core/res/res/drawable/activated_background_holo_light.xml index febf2c4..a29bcb9 100644 --- a/core/res/res/drawable/activated_background_holo_light.xml +++ b/core/res/res/drawable/activated_background_holo_light.xml @@ -14,7 +14,8 @@ limitations under the License. --> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + android:exitFadeDuration="@android:integer/config_mediumAnimTime"> <item android:state_activated="true" android:drawable="@android:drawable/list_activated_holo" /> <item android:drawable="@color/transparent" /> </selector> diff --git a/core/res/res/drawable/activated_background_light.xml b/core/res/res/drawable/activated_background_light.xml index 5d5681d..7d737db 100644 --- a/core/res/res/drawable/activated_background_light.xml +++ b/core/res/res/drawable/activated_background_light.xml @@ -14,7 +14,8 @@ limitations under the License. --> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + android:exitFadeDuration="@android:integer/config_mediumAnimTime"> <item android:state_activated="true" android:drawable="@drawable/list_selector_background_selected_light" /> <item android:drawable="@color/transparent" /> </selector> diff --git a/core/res/res/drawable/list_selector_background.xml b/core/res/res/drawable/list_selector_background.xml index 6fb0661..f5eb12d 100644 --- a/core/res/res/drawable/list_selector_background.xml +++ b/core/res/res/drawable/list_selector_background.xml @@ -14,7 +14,8 @@ limitations under the License. --> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + android:exitFadeDuration="@android:integer/config_mediumAnimTime"> <item android:state_window_focused="false" android:drawable="@color/transparent" /> diff --git a/core/res/res/drawable/list_selector_background_light.xml b/core/res/res/drawable/list_selector_background_light.xml index 4da7e21..50a821b 100644 --- a/core/res/res/drawable/list_selector_background_light.xml +++ b/core/res/res/drawable/list_selector_background_light.xml @@ -14,7 +14,8 @@ limitations under the License. --> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + android:exitFadeDuration="@android:integer/config_mediumAnimTime"> <item android:state_window_focused="false" android:drawable="@color/transparent" /> diff --git a/core/res/res/drawable/list_selector_holo_dark.xml b/core/res/res/drawable/list_selector_holo_dark.xml index e4c5c52..9a6cb89 100644 --- a/core/res/res/drawable/list_selector_holo_dark.xml +++ b/core/res/res/drawable/list_selector_holo_dark.xml @@ -14,7 +14,8 @@ limitations under the License. --> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + android:exitFadeDuration="@android:integer/config_mediumAnimTime"> <item android:state_window_focused="false" android:drawable="@color/transparent" /> diff --git a/core/res/res/drawable/list_selector_holo_light.xml b/core/res/res/drawable/list_selector_holo_light.xml index 17631bd..844259e 100644 --- a/core/res/res/drawable/list_selector_holo_light.xml +++ b/core/res/res/drawable/list_selector_holo_light.xml @@ -14,7 +14,8 @@ limitations under the License. --> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + android:exitFadeDuration="@android:integer/config_mediumAnimTime"> <item android:state_window_focused="false" android:drawable="@color/transparent" /> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index a2fa1a3..1083452 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2786,6 +2786,10 @@ same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with an RGB 565 screen). --> <attr name="dither" format="boolean" /> + <!-- Amount of time (in milliseconds) to fade in a new state drawable. --> + <attr name="enterFadeDuration" format="integer" /> + <!-- Amount of time (in milliseconds) to fade out an old state drawable. --> + <attr name="exitFadeDuration" format="integer" /> </declare-styleable> <declare-styleable name="AnimationDrawable"> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index fd7e984..f8752d3 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1358,6 +1358,8 @@ <public type="attr" name="buttonGroupStyle" /> <public type="attr" name="alertDialogButtonGroupStyle" /> <public type="attr" name="homeAsUpIndicator" /> + <public type="attr" name="enterFadeDuration" /> + <public type="attr" name="exitFadeDuration" /> <public type="anim" name="animator_fade_in" /> <public type="anim" name="animator_fade_out" /> diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 7b2d9d7..baa9d62 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -423,6 +423,13 @@ public abstract class Drawable { } /** + * If this Drawable does transition animations between states, ask that + * it immediately jump to the current state and skip any active animations. + */ + public void jumpToCurrentState() { + } + + /** * @return The current drawable that will be used by this drawable. For simple drawables, this * is just the drawable itself. For drawables that change state like * {@link StateListDrawable} and {@link LevelListDrawable} this will be the child drawable diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 124d907..e55a746 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -21,6 +21,7 @@ import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.os.SystemClock; /** * A helper class that contains several {@link Drawable}s and selects which one to use. @@ -28,6 +29,8 @@ import android.graphics.Rect; * You can subclass it to create your own DrawableContainers or directly use one its child classes. */ public class DrawableContainer extends Drawable implements Drawable.Callback { + private static final boolean DEBUG = false; + private static final String TAG = "DrawableContainer"; /** * To be proper, we should have a getter for dither (and alpha, etc.) @@ -48,6 +51,12 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { private int mCurIndex = -1; private boolean mMutated; + // Animations. + private Runnable mAnimationRunnable; + private long mEnterAnimationEnd; + private long mExitAnimationEnd; + private Drawable mLastDrawable; + // overrides from Drawable @Override @@ -55,6 +64,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (mCurrDrawable != null) { mCurrDrawable.draw(canvas); } + if (mLastDrawable != null) { + mLastDrawable.draw(canvas); + } } @Override @@ -83,7 +95,11 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (mAlpha != alpha) { mAlpha = alpha; if (mCurrDrawable != null) { - mCurrDrawable.setAlpha(alpha); + if (mEnterAnimationEnd == 0) { + mCurrDrawable.setAlpha(alpha); + } else { + animate(false); + } } } } @@ -108,8 +124,29 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } } + /** + * Change the global fade duration when a new drawable is entering + * the scene. + * @param ms The amount of time to fade in milliseconds. + */ + public void setEnterFadeDuration(int ms) { + mDrawableContainerState.mEnterFadeDuration = ms; + } + + /** + * Change the global fade duration when a new drawable is leaving + * the scene. + * @param ms The amount of time to fade in milliseconds. + */ + public void setExitFadeDuration(int ms) { + mDrawableContainerState.mExitFadeDuration = ms; + } + @Override protected void onBoundsChange(Rect bounds) { + if (mLastDrawable != null) { + mLastDrawable.setBounds(bounds); + } if (mCurrDrawable != null) { mCurrDrawable.setBounds(bounds); } @@ -121,7 +158,34 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } @Override + public void jumpToCurrentState() { + boolean changed = false; + if (mLastDrawable != null) { + mLastDrawable.jumpToCurrentState(); + mLastDrawable = null; + changed = true; + } + if (mCurrDrawable != null) { + mCurrDrawable.jumpToCurrentState(); + } + if (mExitAnimationEnd != 0) { + mExitAnimationEnd = 0; + changed = true; + } + if (mEnterAnimationEnd != 0) { + mEnterAnimationEnd = 0; + changed = true; + } + if (changed) { + invalidateSelf(); + } + } + + @Override protected boolean onStateChange(int[] state) { + if (mLastDrawable != null) { + return mLastDrawable.setState(state); + } if (mCurrDrawable != null) { return mCurrDrawable.setState(state); } @@ -130,6 +194,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { @Override protected boolean onLevelChange(int level) { + if (mLastDrawable != null) { + return mLastDrawable.setLevel(level); + } if (mCurrDrawable != null) { return mCurrDrawable.setLevel(level); } @@ -168,22 +235,19 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return mCurrDrawable != null ? mCurrDrawable.getMinimumHeight() : 0; } - public void invalidateDrawable(Drawable who) - { + public void invalidateDrawable(Drawable who) { if (who == mCurrDrawable && mCallback != null) { mCallback.invalidateDrawable(this); } } - public void scheduleDrawable(Drawable who, Runnable what, long when) - { + public void scheduleDrawable(Drawable who, Runnable what, long when) { if (who == mCurrDrawable && mCallback != null) { mCallback.scheduleDrawable(this, what, when); } } - public void unscheduleDrawable(Drawable who, Runnable what) - { + public void unscheduleDrawable(Drawable who, Runnable what) { if (who == mCurrDrawable && mCallback != null) { mCallback.unscheduleDrawable(this, what); } @@ -192,6 +256,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { @Override public boolean setVisible(boolean visible, boolean restart) { boolean changed = super.setVisible(visible, restart); + if (mLastDrawable != null) { + mLastDrawable.setVisible(visible, restart); + } if (mCurrDrawable != null) { mCurrDrawable.setVisible(visible, restart); } @@ -208,16 +275,39 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (idx == mCurIndex) { return false; } - if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) { - Drawable d = mDrawableContainerState.mDrawables[idx]; + + final long now = SystemClock.uptimeMillis(); + + if (DEBUG) android.util.Log.i(TAG, toString() + " from " + mCurIndex + " to " + idx + + ": exit=" + mDrawableContainerState.mExitFadeDuration + + " enter=" + mDrawableContainerState.mEnterFadeDuration); + + if (mDrawableContainerState.mExitFadeDuration > 0) { + if (mLastDrawable != null) { + mLastDrawable.setVisible(false, false); + } if (mCurrDrawable != null) { - mCurrDrawable.setVisible(false, false); + mLastDrawable = mCurrDrawable; + mExitAnimationEnd = now + mDrawableContainerState.mExitFadeDuration; + } else { + mLastDrawable = null; + mExitAnimationEnd = 0; } + } else if (mCurrDrawable != null) { + mCurrDrawable.setVisible(false, false); + } + + if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) { + Drawable d = mDrawableContainerState.mDrawables[idx]; mCurrDrawable = d; mCurIndex = idx; if (d != null) { + if (mDrawableContainerState.mEnterFadeDuration > 0) { + mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration; + } else { + d.setAlpha(mAlpha); + } d.setVisible(isVisible(), true); - d.setAlpha(mAlpha); d.setDither(mDrawableContainerState.mDither); d.setColorFilter(mColorFilter); d.setState(getState()); @@ -225,16 +315,72 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { d.setBounds(getBounds()); } } else { - if (mCurrDrawable != null) { - mCurrDrawable.setVisible(false, false); - } mCurrDrawable = null; mCurIndex = -1; } + + if (mEnterAnimationEnd != 0 || mExitAnimationEnd != 0) { + if (mAnimationRunnable == null) { + mAnimationRunnable = new Runnable() { + @Override public void run() { + animate(true); + invalidateSelf(); + } + }; + } else { + unscheduleSelf(mAnimationRunnable); + } + // Compute first frame and schedule next animation. + animate(true); + } + invalidateSelf(); + return true; } + void animate(boolean schedule) { + final long now = SystemClock.uptimeMillis(); + boolean animating = false; + if (mCurrDrawable != null) { + if (mEnterAnimationEnd != 0) { + if (mEnterAnimationEnd <= now) { + mCurrDrawable.setAlpha(mAlpha); + mEnterAnimationEnd = 0; + } else { + int animAlpha = (int)((mEnterAnimationEnd-now)*255) + / mDrawableContainerState.mEnterFadeDuration; + if (DEBUG) android.util.Log.i(TAG, toString() + " cur alpha " + animAlpha); + mCurrDrawable.setAlpha(((255-animAlpha)*mAlpha)/255); + animating = true; + } + } + } else { + mEnterAnimationEnd = 0; + } + if (mLastDrawable != null) { + if (mExitAnimationEnd != 0) { + if (mExitAnimationEnd <= now) { + mLastDrawable.setVisible(false, false); + mLastDrawable = null; + mExitAnimationEnd = 0; + } else { + int animAlpha = (int)((mExitAnimationEnd-now)*255) + / mDrawableContainerState.mExitFadeDuration; + if (DEBUG) android.util.Log.i(TAG, toString() + " last alpha " + animAlpha); + mLastDrawable.setAlpha((animAlpha*mAlpha)/255); + animating = true; + } + } + } else { + mExitAnimationEnd = 0; + } + + if (schedule && animating) { + scheduleSelf(mAnimationRunnable, now + 1000/60); + } + } + @Override public Drawable getCurrent() { return mCurrDrawable; @@ -300,6 +446,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { boolean mDither = DEFAULT_DITHER; + int mEnterFadeDuration; + int mExitFadeDuration; + DrawableContainerState(DrawableContainerState orig, DrawableContainer owner, Resources res) { mOwner = owner; @@ -340,6 +489,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mDither = orig.mDither; + mEnterFadeDuration = orig.mEnterFadeDuration; + mExitFadeDuration = orig.mExitFadeDuration; + } else { mDrawables = new Drawable[10]; mNumChildren = 0; @@ -476,6 +628,22 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } } + public final void setEnterFadeDuration(int duration) { + mEnterFadeDuration = duration; + } + + public final int getEnterFadeDuration() { + return mEnterFadeDuration; + } + + public final void setExitFadeDuration(int duration) { + mExitFadeDuration = duration; + } + + public final int getExitFadeDuration() { + return mExitFadeDuration; + } + public final int getOpacity() { if (mHaveOpacity) { return mOpacity; diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index 239be40..384ca81 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -20,6 +20,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.util.Arrays; import android.content.res.Resources; import android.content.res.TypedArray; @@ -44,6 +45,7 @@ import android.util.StateSet; * @attr ref android.R.styleable#DrawableStates_state_checkable * @attr ref android.R.styleable#DrawableStates_state_checked * @attr ref android.R.styleable#DrawableStates_state_selected + * @attr ref android.R.styleable#DrawableStates_state_activated * @attr ref android.R.styleable#DrawableStates_state_active * @attr ref android.R.styleable#DrawableStates_state_single * @attr ref android.R.styleable#DrawableStates_state_first @@ -52,6 +54,9 @@ import android.util.StateSet; * @attr ref android.R.styleable#DrawableStates_state_pressed */ public class StateListDrawable extends DrawableContainer { + private static final boolean DEBUG = false; + private static final String TAG = "StateListDrawable"; + /** * To be proper, we should have a getter for dither (and alpha, etc.) * so that proxy classes like this can save/restore their delegates' @@ -93,6 +98,8 @@ public class StateListDrawable extends DrawableContainer { @Override protected boolean onStateChange(int[] stateSet) { int idx = mStateListState.indexOfStateSet(stateSet); + if (DEBUG) android.util.Log.i(TAG, "onStateChange " + this + " states " + + Arrays.toString(stateSet) + " found " + idx); if (idx < 0) { idx = mStateListState.indexOfStateSet(StateSet.WILD_CARD); } @@ -117,6 +124,10 @@ public class StateListDrawable extends DrawableContainer { com.android.internal.R.styleable.StateListDrawable_variablePadding, false)); mStateListState.setConstantSize(a.getBoolean( com.android.internal.R.styleable.StateListDrawable_constantSize, false)); + mStateListState.setEnterFadeDuration(a.getInt( + com.android.internal.R.styleable.StateListDrawable_enterFadeDuration, 0)); + mStateListState.setExitFadeDuration(a.getInt( + com.android.internal.R.styleable.StateListDrawable_exitFadeDuration, 0)); setDither(a.getBoolean(com.android.internal.R.styleable.StateListDrawable_dither, DEFAULT_DITHER)); @@ -251,7 +262,7 @@ public class StateListDrawable extends DrawableContainer { } static final class StateListState extends DrawableContainerState { - private int[][] mStateSets; + int[][] mStateSets; StateListState(StateListState orig, StateListDrawable owner, Resources res) { super(orig, owner, res); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 855a4e0..09e01f6 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -260,25 +260,25 @@ int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, const GLuint previousFbo = mSnapshot->fbo; const int count = saveSnapshot(flags); - int alpha = 255; - SkXfermode::Mode mode; - - if (p) { - alpha = p->getAlpha(); - if (!mCaches.extensions.hasFramebufferFetch()) { - const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); - if (!isMode) { - // Assume SRC_OVER - mode = SkXfermode::kSrcOver_Mode; + if (!mSnapshot->invisible) { + int alpha = 255; + SkXfermode::Mode mode; + + if (p) { + alpha = p->getAlpha(); + if (!mCaches.extensions.hasFramebufferFetch()) { + const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); + if (!isMode) { + // Assume SRC_OVER + mode = SkXfermode::kSrcOver_Mode; + } + } else { + mode = getXfermode(p->getXfermode()); } } else { - mode = getXfermode(p->getXfermode()); + mode = SkXfermode::kSrcOver_Mode; } - } else { - mode = SkXfermode::kSrcOver_Mode; - } - if (!mSnapshot->previous->invisible) { createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags, previousFbo); } @@ -379,8 +379,7 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, bounds.getHeight() > mCaches.maxTextureSize) { snapshot->invisible = true; } else { - snapshot->invisible = snapshot->previous->invisible || - (alpha <= ALPHA_THRESHOLD && fboLayer); + snapshot->invisible = snapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer); } // Bail out if we won't draw in this snapshot @@ -1011,6 +1010,9 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { } void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { + // No need to check against the clip, we fill the clip region + if (mSnapshot->invisible) return; + Rect& clip(*mSnapshot->clipRect); clip.snapToPixelBoundaries(); drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true); diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java index 4644a7c..50d10bf 100644 --- a/policy/src/com/android/internal/policy/impl/LockScreen.java +++ b/policy/src/com/android/internal/policy/impl/LockScreen.java @@ -219,7 +219,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, } class WaveViewMethods implements WaveView.OnTriggerListener { - private static final int WAIT_FOR_ANIMATION_TIMEOUT = 500; + private static final int WAIT_FOR_ANIMATION_TIMEOUT = 0; private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000; /** {@inheritDoc} */ diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java index 185d413..c3ad9e6 100644 --- a/telephony/java/com/android/internal/telephony/DataConnection.java +++ b/telephony/java/com/android/internal/telephony/DataConnection.java @@ -261,8 +261,10 @@ public abstract class DataConnection extends HierarchicalStateMachine { protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100; //***** Member Variables + protected int mId; protected int mTag; protected PhoneBase phone; + protected RetryManager mRetryMgr; protected int cid; protected LinkProperties mLinkProperties = new LinkProperties(); protected LinkCapabilities mCapabilities = new LinkCapabilities(); @@ -285,10 +287,11 @@ public abstract class DataConnection extends HierarchicalStateMachine { //***** Constructor - protected DataConnection(PhoneBase phone, String name) { + protected DataConnection(PhoneBase phone, String name, RetryManager rm) { super(name); if (DBG) log("DataConnection constructor E"); this.phone = phone; + mRetryMgr = rm; this.cid = -1; clearSettings(); @@ -358,8 +361,8 @@ public abstract class DataConnection extends HierarchicalStateMachine { if (dp.onCompletedMsg != null) { Message msg = dp.onCompletedMsg; - log(String.format("msg.what=%d msg.obj=%s", - msg.what, ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>"))); + log(String.format("msg=%s msg.obj=%s", msg.toString(), + ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>"))); AsyncResult.forMessage(msg); msg.sendToTarget(); } @@ -372,6 +375,10 @@ public abstract class DataConnection extends HierarchicalStateMachine { clearSettings(); } + public RetryManager getRetryMgr() { + return mRetryMgr; + } + /** * Clear all settings called when entering mInactiveState. */ @@ -857,13 +864,13 @@ public abstract class DataConnection extends HierarchicalStateMachine { /** * Connect to the apn and return an AsyncResult in onCompletedMsg. - * Used for cellular networks that use Acess Point Names (APN) such + * Used for cellular networks that use Acesss Point Names (APN) such * as GSM networks. * * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. * With AsyncResult.userObj set to the original msg.obj, * AsyncResult.result = FailCause and AsyncResult.exception = Exception(). - * @param apn is the Acces Point Name to connect to + * @param apn is the Access Point Name to connect to */ public void connect(Message onCompletedMsg, ApnSetting apn) { sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apn, onCompletedMsg))); @@ -915,6 +922,13 @@ public abstract class DataConnection extends HierarchicalStateMachine { } /** + * Get the DataConnection ID + */ + public int getDataConnectionId() { + return mId; + } + + /** * Return the LinkProperties for the connection. * * @return a copy of the LinkProperties, is never null. diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java index 52839be..f8812ec 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -16,27 +16,38 @@ package com.android.internal.telephony; +import com.android.internal.telephony.cdma.CDMAPhone; + import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.net.IConnectivityManager; import android.net.LinkCapabilities; import android.net.LinkProperties; +import android.net.NetworkInfo; +import android.net.wifi.WifiManager; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; +import android.os.ServiceManager; +import android.preference.PreferenceManager; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.text.TextUtils; import android.util.Log; import java.util.ArrayList; - +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicInteger; /** * {@hide} - * */ public abstract class DataConnectionTracker extends Handler { - protected static final boolean DBG = false; - protected final String LOG_TAG = "DataConnectionTracker"; + protected static final boolean DBG = true; /** * IDLE: ready to start data connection setup, default state @@ -121,9 +132,10 @@ public abstract class DataConnectionTracker extends Handler { protected boolean mMasterDataEnabled = true; protected boolean[] dataEnabled = new boolean[APN_NUM_TYPES]; + protected int enabledCount = 0; - /* Currently requested APN type */ + /* Currently requested APN type (TODO: This should probably be a parameter not a member) */ protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT; /** Retry configuration: A doubling of retry times from 5secs to 30minutes */ @@ -165,20 +177,27 @@ public abstract class DataConnectionTracker extends Handler { // represents an invalid IP address protected static final String NULL_IP = "0.0.0.0"; + // TODO: See if we can remove INTENT_RECONNECT_ALARM + // having to have different values for GSM and + // CDMA. If so we can then remove the need for + // getActionIntentReconnectAlarm. + protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason"; // member variables - protected PhoneBase phone; - protected Activity activity = Activity.NONE; - protected State state = State.IDLE; + protected PhoneBase mPhone; + protected Activity mActivity = Activity.NONE; + protected State mState = State.IDLE; protected Handler mDataConnectionTracker = null; - protected long txPkts, rxPkts, sentSinceLastRecv; - protected int netStatPollPeriod; + protected long mTxPkts; + protected long mRxPkts; + protected long mSentSinceLastRecv; + protected int mNetStatPollPeriod; protected int mNoRecvPollCount = 0; - protected boolean netStatPollEnabled = false; + protected boolean mNetStatPollEnabled = false; - /** Manage the behavior of data retry after failure */ + /** Manage the behavior of data retry after failure (TODO: One per connection in the future?) */ protected RetryManager mRetryMgr = new RetryManager(); // wifi connection status will be updated by sticky intent @@ -188,37 +207,125 @@ public abstract class DataConnectionTracker extends Handler { protected PendingIntent mReconnectIntent = null; /** CID of active data connection */ - protected int cidActive; + protected int mCidActive; /** indication of our availability (preconditions to trysetupData are met) **/ protected boolean mAvailability = false; + // When false we will not auto attach and manully attaching is required. + protected boolean mAutoAttachOnCreation = false; + + // State of screen + // (TODO: Reconsider tying directly to screen, maybe this is + // really a lower power mode") + protected boolean mIsScreenOn = true; + /** The link properties (dns, gateway, ip, etc) */ protected LinkProperties mLinkProperties = new LinkProperties(); /** The link capabilities */ protected LinkCapabilities mLinkCapabilities = new LinkCapabilities(); + /** Allows the generation of unique Id's for DataConnection objects */ + protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0); + + /** The data connections. */ + protected HashMap<Integer, DataConnection> mDataConnections = + new HashMap<Integer, DataConnection>(); + + protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver () + { + @Override + public void onReceive(Context context, Intent intent) + { + String action = intent.getAction(); + if (action.equals(Intent.ACTION_SCREEN_ON)) { + mIsScreenOn = true; + stopNetStatPoll(); + startNetStatPoll(); + } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { + mIsScreenOn = false; + stopNetStatPoll(); + startNetStatPoll(); + } else if (action.equals(getActionIntentReconnectAlarm())) { + log("Reconnect alarm. Previous state was " + mState); + + String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON); + if (mState == State.FAILED) { + Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); + msg.arg1 = 0; // tearDown is false + msg.obj = reason; + sendMessage(msg); + } + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); + } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { + final android.net.NetworkInfo networkInfo = (NetworkInfo) + intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); + mIsWifiConnected = (networkInfo != null && networkInfo.isConnected()); + } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { + final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, + WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; + + if (!enabled) { + // when WiFi got disabled, the NETWORK_STATE_CHANGED_ACTION + // quit and won't report disconnected until next enabling. + mIsWifiConnected = false; + } + } + } + }; + /** * Default constructor */ protected DataConnectionTracker(PhoneBase phone) { super(); - this.phone = phone; + mPhone = phone; + + IntentFilter filter = new IntentFilter(); + filter.addAction(getActionIntentReconnectAlarm()); + filter.addAction(Intent.ACTION_SCREEN_ON); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + + // TODO: Why is this registering the phone as the receiver of the intent + // and not its own handler? + mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); + + // This preference tells us 1) initial condition for "dataEnabled", + // and 2) whether the RIL will setup the baseband to auto-PS attach. + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext()); + boolean dataEnabledSetting = true; + try { + dataEnabledSetting = IConnectivityManager.Stub.asInterface(ServiceManager. + getService(Context.CONNECTIVITY_SERVICE)).getMobileDataEnabled(); + } catch (Exception e) { + // nothing to do - use the old behavior and leave data on + } + dataEnabled[APN_DEFAULT_ID] = + !sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false) && + dataEnabledSetting; + if (dataEnabled[APN_DEFAULT_ID]) { + enabledCount++; + } + mAutoAttachOnCreation = dataEnabled[APN_DEFAULT_ID]; } - public abstract void dispose(); + public void dispose() { + mPhone.getContext().unregisterReceiver(this.mIntentReceiver); + } public Activity getActivity() { - return activity; + return mActivity; } public State getState() { - return state; + return mState; } public String getStateInString() { - switch (state) { + switch (mState) { case IDLE: return "IDLE"; case INITING: return "INIT"; case CONNECTING: return "CING"; @@ -231,6 +338,14 @@ public abstract class DataConnectionTracker extends Handler { } /** + * @return the data connections + */ + public ArrayList<DataConnection> getAllDataConnections() { + /** TODO: change return type to Collection? */ + return new ArrayList<DataConnection>(mDataConnections.values()); + } + + /** * The data connection is expected to be setup while device * 1. has Icc card * 2. registered for data service @@ -246,9 +361,9 @@ public abstract class DataConnectionTracker extends Handler { // the shared values. If it is not, then update it. public void setDataOnRoamingEnabled(boolean enabled) { if (getDataOnRoamingEnabled() != enabled) { - Settings.Secure.putInt(phone.getContext().getContentResolver(), + Settings.Secure.putInt(mPhone.getContext().getContentResolver(), Settings.Secure.DATA_ROAMING, enabled ? 1 : 0); - if (phone.getServiceState().getRoaming()) { + if (mPhone.getServiceState().getRoaming()) { if (enabled) { mRetryMgr.resetRetryCount(); } @@ -257,16 +372,19 @@ public abstract class DataConnectionTracker extends Handler { } } - //Retrieve the data roaming setting from the shared preferences. + // Retrieve the data roaming setting from the shared preferences. public boolean getDataOnRoamingEnabled() { try { - return Settings.Secure.getInt(phone.getContext().getContentResolver(), - Settings.Secure.DATA_ROAMING) > 0; + return Settings.Secure.getInt( + mPhone.getContext().getContentResolver(), Settings.Secure.DATA_ROAMING) > 0; } catch (SettingNotFoundException snfe) { return false; } } + + protected abstract String getActionIntentReconnectAlarm(); + // abstract handler methods protected abstract boolean onTrySetupData(String reason); protected abstract void onRoamingOff(); @@ -274,14 +392,14 @@ public abstract class DataConnectionTracker extends Handler { protected abstract void onRadioAvailable(); protected abstract void onRadioOffOrNotAvailable(); protected abstract void onDataSetupComplete(AsyncResult ar); - protected abstract void onDisconnectDone(AsyncResult ar); + protected abstract void onDisconnectDone(int connId, AsyncResult ar); protected abstract void onResetDone(AsyncResult ar); protected abstract void onVoiceCallStarted(); protected abstract void onVoiceCallEnded(); protected abstract void onCleanUpConnection(boolean tearDown, String reason); @Override - public void handleMessage (Message msg) { + public void handleMessage(Message msg) { switch (msg.what) { case EVENT_ENABLE_NEW_APN: @@ -291,7 +409,7 @@ public abstract class DataConnectionTracker extends Handler { case EVENT_TRY_SETUP_DATA: String reason = null; if (msg.obj instanceof String) { - reason = (String)msg.obj; + reason = (String) msg.obj; } onTrySetupData(reason); break; @@ -316,12 +434,13 @@ public abstract class DataConnectionTracker extends Handler { break; case EVENT_DATA_SETUP_COMPLETE: - cidActive = msg.arg1; + mCidActive = msg.arg1; onDataSetupComplete((AsyncResult) msg.obj); break; case EVENT_DISCONNECT_DONE: - onDisconnectDone((AsyncResult) msg.obj); + log("DataConnectoinTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg); + onDisconnectDone(msg.arg1, (AsyncResult) msg.obj); break; case EVENT_VOICE_CALL_STARTED: @@ -334,7 +453,7 @@ public abstract class DataConnectionTracker extends Handler { case EVENT_CLEAN_UP_CONNECTION: boolean tearDown = (msg.arg1 == 0) ? false : true; - onCleanUpConnection(tearDown, (String)msg.obj); + onCleanUpConnection(tearDown, (String) msg.obj); break; case EVENT_SET_MASTER_DATA_ENABLE: @@ -354,8 +473,9 @@ public abstract class DataConnectionTracker extends Handler { /** * Report the current state of data connectivity (enabled or disabled) + * * @return {@code false} if data connectivity has been explicitly disabled, - * {@code true} otherwise. + * {@code true} otherwise. */ public synchronized boolean getDataEnabled() { return dataEnabled[APN_DEFAULT_ID]; @@ -363,8 +483,9 @@ public abstract class DataConnectionTracker extends Handler { /** * Report on whether data connectivity is enabled + * * @return {@code false} if data connectivity has been explicitly disabled, - * {@code true} otherwise. + * {@code true} otherwise. */ public boolean getAnyDataEnabled() { return (enabledCount != 0); @@ -378,6 +499,8 @@ public abstract class DataConnectionTracker extends Handler { protected abstract void log(String s); + protected abstract void loge(String s); + protected int apnTypeToId(String type) { if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) { return APN_DEFAULT_ID; @@ -407,7 +530,7 @@ public abstract class DataConnectionTracker extends Handler { case APN_HIPRI_ID: return Phone.APN_TYPE_HIPRI; default: - Log.e(LOG_TAG, "Unknown id (" + id + ") in apnIdToType"); + log("Unknown id (" + id + ") in apnIdToType"); return Phone.APN_TYPE_DEFAULT; } } @@ -420,8 +543,6 @@ public abstract class DataConnectionTracker extends Handler { protected abstract String getActiveApnString(); - public abstract ArrayList<DataConnection> getAllDataConnections(); - protected abstract void setState(State s); protected LinkProperties getLinkProperties(String apnType) { @@ -467,33 +588,34 @@ public abstract class DataConnectionTracker extends Handler { protected void notifyDataConnection(String reason) { for (int id = 0; id < APN_NUM_TYPES; id++) { if (dataEnabled[id]) { - phone.notifyDataConnection(reason, apnIdToType(id)); + mPhone.notifyDataConnection(reason, apnIdToType(id)); } } notifyDataAvailability(reason); } - // a new APN has gone active and needs to send events to catch up with the current condition + // a new APN has gone active and needs to send events to catch up with the + // current condition private void notifyApnIdUpToCurrent(String reason, int apnId) { - switch (state) { + switch (mState) { case IDLE: case INITING: break; case CONNECTING: case SCANNING: - phone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING); + mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING); break; case CONNECTED: case DISCONNECTING: - phone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING); - phone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTED); + mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING); + mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTED); break; } } // since we normally don't send info to a disconnected APN, we need to do this specially private void notifyApnIdDisconnected(String reason, int apnId) { - phone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.DISCONNECTED); + mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.DISCONNECTED); } // disabled apn's still need avail/unavail notificiations - send them out @@ -526,10 +648,10 @@ public abstract class DataConnectionTracker extends Handler { * @return {@code true} if data connectivity is possible, {@code false} otherwise. */ protected boolean isDataPossible() { - boolean possible = (isDataAllowed() && - !(getDataEnabled() && (state == State.FAILED || state == State.IDLE))); + boolean possible = (isDataAllowed() + && !(getDataEnabled() && (mState == State.FAILED || mState == State.IDLE))); if (!possible && DBG && isDataAllowed()) { - log("Data not possible. No coverage: dataState = " + state); + log("Data not possible. No coverage: dataState = " + mState); } return possible; } @@ -549,13 +671,13 @@ public abstract class DataConnectionTracker extends Handler { /** * Ensure that we are connected to an APN of the specified type. - * @param type the APN type (currently the only valid values - * are {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}) - * @return the result of the operation. Success is indicated by - * a return value of either {@code Phone.APN_ALREADY_ACTIVE} or - * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a broadcast - * will be sent by the ConnectivityManager when a connection to - * the APN has been established. + * + * @param type the APN type (currently the only valid values are + * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}) + * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or + * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a + * broadcast will be sent by the ConnectivityManager when a + * connection to the APN has been established. */ public synchronized int enableApnType(String type) { int id = apnTypeToId(type); @@ -564,13 +686,12 @@ public abstract class DataConnectionTracker extends Handler { } if (DBG) { - Log.d(LOG_TAG, "enableApnType(" + type + "), isApnTypeActive = " - + isApnTypeActive(type) + ", isApnIdEnabled =" + isApnIdEnabled(id) + - " and state = " + state); + log("enableApnType(" + type + "), isApnTypeActive = " + isApnTypeActive(type) + + ", isApnIdEnabled =" + isApnIdEnabled(id) + " and state = " + mState); } if (!isApnTypeAvailable(type)) { - if (DBG) Log.d(LOG_TAG, "type not available"); + if (DBG) log("type not available"); return Phone.APN_TYPE_NOT_AVAILABLE; } @@ -583,15 +704,21 @@ public abstract class DataConnectionTracker extends Handler { } /** - * The APN of the specified type is no longer needed. Ensure that if - * use of the default APN has not been explicitly disabled, we are connected - * to the default APN. + * The APN of the specified type is no longer needed. Ensure that if use of + * the default APN has not been explicitly disabled, we are connected to the + * default APN. + * * @param type the APN type. The only valid values are currently - * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}. - * @return + * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}. + * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or + * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a + * broadcast will be sent by the ConnectivityManager when a + * connection to the APN has been disconnected. A {@code + * Phone.APN_REQUEST_FAILED} is returned if the type parameter is + * invalid or if the apn wasn't enabled. */ public synchronized int disableApnType(String type) { - if (DBG) Log.d(LOG_TAG, "disableApnType("+type+")"); + if (DBG) log("disableApnType(" + type + ")"); int id = apnTypeToId(type); if (id == APN_INVALID_ID) { return Phone.APN_REQUEST_FAILED; @@ -614,8 +741,8 @@ public abstract class DataConnectionTracker extends Handler { private void setEnabled(int id, boolean enable) { if (DBG) { - Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ") with old state = " - + dataEnabled[id] + " and enabledCount = " + enabledCount); + log("setEnabled(" + id + ", " + enable + ") with old state = " + dataEnabled[id] + + " and enabledCount = " + enabledCount); } Message msg = obtainMessage(EVENT_ENABLE_NEW_APN); msg.arg1 = id; @@ -625,9 +752,10 @@ public abstract class DataConnectionTracker extends Handler { protected synchronized void onEnableApn(int apnId, int enabled) { if (DBG) { - Log.d(LOG_TAG, "EVENT_APN_ENABLE_REQUEST " + apnId + ", " + enabled); - Log.d(LOG_TAG, " dataEnabled = " + dataEnabled[apnId] + ", enabledCount = " - + enabledCount + ", isApnTypeActive = " + isApnTypeActive(apnIdToType(apnId))); + log("EVENT_APN_ENABLE_REQUEST apnId=" + apnId + ", apnType=" + apnIdToType(apnId) + + ", enabled=" + enabled + ", dataEnabled = " + dataEnabled[apnId] + + ", enabledCount = " + enabledCount + ", isApnTypeActive = " + + isApnTypeActive(apnIdToType(apnId))); } if (enabled == ENABLED) { if (!dataEnabled[apnId]) { @@ -676,18 +804,22 @@ public abstract class DataConnectionTracker extends Handler { } /** - * Prevent mobile data connections from being established, - * or once again allow mobile data connections. If the state - * toggles, then either tear down or set up data, as - * appropriate to match the new state. - * <p>This operation only affects the default APN, and if the same APN is - * currently being used for MMS traffic, the teardown will not happen - * even when {@code enable} is {@code false}.</p> - * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data + * Prevent mobile data connections from being established, or once again + * allow mobile data connections. If the state toggles, then either tear + * down or set up data, as appropriate to match the new state. + * <p> + * This operation only affects the default APN, and if the same APN is + * currently being used for MMS traffic, the teardown will not happen even + * when {@code enable} is {@code false}. + * </p> + * + * @param enable indicates whether to enable ({@code true}) or disable ( + * {@code false}) data * @return {@code true} if the operation succeeded */ public boolean setDataEnabled(boolean enable) { - if (DBG) Log.d(LOG_TAG, "setDataEnabled(" + enable + ")"); + if (DBG) + log("setDataEnabled(" + enable + ")"); Message msg = obtainMessage(EVENT_SET_MASTER_DATA_ENABLE); msg.arg1 = (enable ? ENABLED : DISABLED); diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java index 95cb1c6..8072c44 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java @@ -23,6 +23,7 @@ import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.gsm.ApnSetting; import com.android.internal.telephony.Phone; import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.RetryManager; /** * {@hide} @@ -39,23 +40,27 @@ public class CdmaDataConnection extends DataConnection { // ***** Constructor - private CdmaDataConnection(CDMAPhone phone, String name) { - super(phone, name); + private CdmaDataConnection(CDMAPhone phone, String name, RetryManager rm) { + super(phone, name, rm); } /** * Create the connection object * - * @param phone + * @param phone the Phone + * @param id the connection id + * @param rm the RetryManager * @return CdmaDataConnection that was created. */ - static CdmaDataConnection makeDataConnection(CDMAPhone phone) { + static CdmaDataConnection makeDataConnection(CDMAPhone phone, int id, RetryManager rm) { synchronized (mCountLock) { mCount += 1; } - CdmaDataConnection cdmaDc = new CdmaDataConnection(phone, "CdmaDataConnection-" + mCount); + CdmaDataConnection cdmaDc = new CdmaDataConnection(phone, + "CdmaDataConnection-" + mCount, rm); cdmaDc.start(); if (DBG) cdmaDc.log("Made " + cdmaDc.getName()); + cdmaDc.mId = id; return cdmaDc; } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java index e499e95..7c652c5 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java @@ -18,21 +18,13 @@ package com.android.internal.telephony.cdma; import android.app.AlarmManager; import android.app.PendingIntent; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.net.IConnectivityManager; -import android.net.NetworkInfo; import android.net.TrafficStats; -import android.net.wifi.WifiManager; import android.os.AsyncResult; import android.os.Message; -import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; -import android.preference.PreferenceManager; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.telephony.cdma.CdmaCellLocation; @@ -46,6 +38,7 @@ import com.android.internal.telephony.DataConnection.FailCause; import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.DataConnectionTracker; import com.android.internal.telephony.EventLogTags; +import com.android.internal.telephony.RetryManager; import com.android.internal.telephony.gsm.ApnSetting; import com.android.internal.telephony.Phone; @@ -59,20 +52,11 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { private CDMAPhone mCdmaPhone; - // Indicates baseband will not auto-attach - private boolean noAutoAttach = false; - private boolean mIsScreenOn = true; - //useful for debugging - boolean failNextConnect = false; + boolean mFailNextConnect = false; - /** - * dataConnectionList holds all the Data connection - */ - private ArrayList<DataConnection> dataConnectionList; - - /** Currently active CdmaDataConnection */ - private CdmaDataConnection mActiveDataConnection; + /** The DataConnection being setup */ + private CdmaDataConnection mPendingDataConnection; private boolean mPendingRestartRadio = false; private static final int TIME_DELAYED_TO_RESTART_RADIO = @@ -83,10 +67,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { */ private static final int DATA_CONNECTION_POOL_SIZE = 1; - private static final int POLL_CONNECTION_MILLIS = 5 * 1000; private static final String INTENT_RECONNECT_ALARM = - "com.android.internal.telephony.cdma-reconnect"; - private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason"; + "com.android.internal.telephony.cdma-reconnect"; /** * Constants for the data connection activity: @@ -110,49 +92,6 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { // if we have no active Apn this is null protected ApnSetting mActiveApn; - // Possibly promote to base class, the only difference is - // the INTENT_RECONNECT_ALARM action is a different string. - // Do consider technology changes if it is promoted. - BroadcastReceiver mIntentReceiver = new BroadcastReceiver () - { - @Override - public void onReceive(Context context, Intent intent) - { - String action = intent.getAction(); - if (action.equals(Intent.ACTION_SCREEN_ON)) { - mIsScreenOn = true; - stopNetStatPoll(); - startNetStatPoll(); - } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { - mIsScreenOn = false; - stopNetStatPoll(); - startNetStatPoll(); - } else if (action.equals((INTENT_RECONNECT_ALARM))) { - Log.d(LOG_TAG, "Data reconnect alarm. Previous state was " + state); - - String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON); - if (state == State.FAILED) { - cleanUpConnection(false, reason); - } - trySetupData(reason); - } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - final android.net.NetworkInfo networkInfo = (NetworkInfo) - intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); - mIsWifiConnected = (networkInfo != null && networkInfo.isConnected()); - } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; - - if (!enabled) { - // when wifi got disabeled, the NETWORK_STATE_CHANGED_ACTION - // quit and wont report disconnected til next enalbing. - mIsWifiConnected = false; - } - } - } - }; - - /* Constructor */ CdmaDataConnectionTracker(CDMAPhone p) { @@ -172,79 +111,49 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null); p.mCM.registerForCdmaOtaProvision(this, EVENT_CDMA_OTA_PROVISION, null); - IntentFilter filter = new IntentFilter(); - filter.addAction(INTENT_RECONNECT_ALARM); - filter.addAction(Intent.ACTION_SCREEN_ON); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - - // TODO: Why is this registering the phone as the receiver of the intent - // and not its own handler? - p.getContext().registerReceiver(mIntentReceiver, filter, null, p); - mDataConnectionTracker = this; createAllDataConnectionList(); - - // This preference tells us 1) initial condition for "dataEnabled", - // and 2) whether the RIL will setup the baseband to auto-PS attach. - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext()); - - boolean dataEnabledSetting = true; - try { - dataEnabledSetting = IConnectivityManager.Stub.asInterface(ServiceManager. - getService(Context.CONNECTIVITY_SERVICE)).getMobileDataEnabled(); - } catch (Exception e) { - // nothing to do - use the old behavior and leave data on - } - dataEnabled[APN_DEFAULT_ID] = - !sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false) && - dataEnabledSetting; - if (dataEnabled[APN_DEFAULT_ID]) { - enabledCount++; - } - noAutoAttach = !dataEnabled[APN_DEFAULT_ID]; - - if (!mRetryMgr.configure(SystemProperties.get("ro.cdma.data_retry_config"))) { - if (!mRetryMgr.configure(DEFAULT_DATA_RETRY_CONFIG)) { - // Should never happen, log an error and default to a simple linear sequence. - Log.e(LOG_TAG, "Could not configure using DEFAULT_DATA_RETRY_CONFIG=" - + DEFAULT_DATA_RETRY_CONFIG); - mRetryMgr.configure(20, 2000, 1000); - } - } } + @Override public void dispose() { + super.dispose(); + // Unregister from all events - phone.mCM.unregisterForAvailable(this); - phone.mCM.unregisterForOffOrNotAvailable(this); + mPhone.mCM.unregisterForAvailable(this); + mPhone.mCM.unregisterForOffOrNotAvailable(this); mCdmaPhone.mRuimRecords.unregisterForRecordsLoaded(this); - phone.mCM.unregisterForNVReady(this); - phone.mCM.unregisterForDataStateChanged(this); + mPhone.mCM.unregisterForNVReady(this); + mPhone.mCM.unregisterForDataStateChanged(this); mCdmaPhone.mCT.unregisterForVoiceCallEnded(this); mCdmaPhone.mCT.unregisterForVoiceCallStarted(this); mCdmaPhone.mSST.unregisterForCdmaDataConnectionAttached(this); mCdmaPhone.mSST.unregisterForCdmaDataConnectionDetached(this); mCdmaPhone.mSST.unregisterForRoamingOn(this); mCdmaPhone.mSST.unregisterForRoamingOff(this); - phone.mCM.unregisterForCdmaOtaProvision(this); + mPhone.mCM.unregisterForCdmaOtaProvision(this); - phone.getContext().unregisterReceiver(this.mIntentReceiver); destroyAllDataConnectionList(); } + @Override protected void finalize() { - if(DBG) Log.d(LOG_TAG, "CdmaDataConnectionTracker finalized"); + if(DBG) log("CdmaDataConnectionTracker finalized"); + } + + @Override + protected String getActionIntentReconnectAlarm() { + return INTENT_RECONNECT_ALARM; } + @Override protected void setState(State s) { if (DBG) log ("setState: " + s); - if (state != s) { + if (mState != s) { EventLog.writeEvent(EventLogTags.CDMA_DATA_STATE_CHANGE, - state.toString(), s.toString()); - state = s; + mState.toString(), s.toString()); + mState = s; } } @@ -263,6 +172,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { return false; } + @Override protected String[] getActiveApnTypes() { String[] result; if (mActiveApn != null) { @@ -274,6 +184,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { return result; } + @Override protected String getActiveApnString() { return null; } @@ -287,45 +198,51 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { * * @return false while no data connection if all above requirements are met. */ + @Override public boolean isDataConnectionAsDesired() { - boolean roaming = phone.getServiceState().getRoaming(); + boolean roaming = mPhone.getServiceState().getRoaming(); - if (((phone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) || + if (((mPhone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) || mCdmaPhone.mRuimRecords.getRecordsLoaded()) && (mCdmaPhone.mSST.getCurrentCdmaDataConnectionState() == ServiceState.STATE_IN_SERVICE) && (!roaming || getDataOnRoamingEnabled()) && !mIsWifiConnected ) { - return (state == State.CONNECTED); + return (mState == State.CONNECTED); } return true; } + @Override protected boolean isDataAllowed() { int psState = mCdmaPhone.mSST.getCurrentCdmaDataConnectionState(); - boolean roaming = (phone.getServiceState().getRoaming() && !getDataOnRoamingEnabled()); + boolean roaming = (mPhone.getServiceState().getRoaming() && !getDataOnRoamingEnabled()); boolean desiredPowerState = mCdmaPhone.mSST.getDesiredPowerState(); - boolean allowed = (psState == ServiceState.STATE_IN_SERVICE && - (phone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY || - mCdmaPhone.mRuimRecords.getRecordsLoaded()) && - (mCdmaPhone.mSST.isConcurrentVoiceAndData() || - phone.getState() == Phone.State.IDLE) && - !roaming && - mMasterDataEnabled && - desiredPowerState && - !mPendingRestartRadio && - !mCdmaPhone.needsOtaServiceProvisioning()); + boolean allowed = + (psState == ServiceState.STATE_IN_SERVICE || + mAutoAttachOnCreation) && + (mPhone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY || + mCdmaPhone.mRuimRecords.getRecordsLoaded()) && + (mCdmaPhone.mSST.isConcurrentVoiceAndData() || + mPhone.getState() == Phone.State.IDLE) && + !roaming && + mMasterDataEnabled && + desiredPowerState && + !mPendingRestartRadio && + !mCdmaPhone.needsOtaServiceProvisioning(); if (!allowed && DBG) { String reason = ""; - if (psState != ServiceState.STATE_IN_SERVICE) reason += " - psState= " + psState; - if (phone.mCM.getRadioState() != CommandsInterface.RadioState.NV_READY && - !mCdmaPhone.mRuimRecords.getRecordsLoaded()) { - reason += " - radioState= " + phone.mCM.getRadioState() + " - RUIM not loaded"; + if (!((psState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) { + reason += " - psState= " + psState; + } + if (!(mPhone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY || + mCdmaPhone.mRuimRecords.getRecordsLoaded())) { + reason += " - radioState= " + mPhone.mCM.getRadioState() + " - RUIM not loaded"; } - if (phone.getState() != Phone.State.IDLE && + if (mPhone.getState() != Phone.State.IDLE && mCdmaPhone.mSST.isConcurrentVoiceAndData()) { - reason += " - concurrentVoiceAndData not allowed and state= " + phone.getState(); + reason += " - concurrentVoiceAndData not allowed and state= " + mPhone.getState(); } if (roaming) reason += " - Roaming"; if (!mMasterDataEnabled) reason += " - mMasterDataEnabled= false"; @@ -340,22 +257,22 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { private boolean trySetupData(String reason) { if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason)); - if (phone.getSimulatedRadioControl() != null) { + if (mPhone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator // FIXME this can be improved setState(State.CONNECTED); notifyDataConnection(reason); notifyOffApnsOfAvailability(reason, true); - Log.i(LOG_TAG, "(fix?) We're on the simulator; assuming data is connected"); + log("(fix?) We're on the simulator; assuming data is connected"); return true; } int psState = mCdmaPhone.mSST.getCurrentCdmaDataConnectionState(); - boolean roaming = phone.getServiceState().getRoaming(); + boolean roaming = mPhone.getServiceState().getRoaming(); boolean desiredPowerState = mCdmaPhone.mSST.getDesiredPowerState(); - if ((state == State.IDLE || state == State.SCANNING) && + if ((mState == State.IDLE || mState == State.SCANNING) && isDataAllowed() && getAnyDataEnabled()) { boolean retValue = setupData(reason); notifyOffApnsOfAvailability(reason, retValue); @@ -367,13 +284,12 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } /** - * If tearDown is true, this only tears down a CONNECTED session. Presently, - * there is no mechanism for abandoning an INITING/CONNECTING session, - * but would likely involve cancelling pending async requests or - * setting a flag or new state to ignore them when they came in - * @param tearDown true if the underlying DataConnection should be - * disconnected. - * @param reason reason for the clean up. + * Cleanup all connections. + * + * TODO: Cleanup only a specified connection passed as a parameter. + * + * @param tearDown true if the underlying DataConnection should be disconnected. + * @param reason for the clean up. */ private void cleanUpConnection(boolean tearDown, String reason) { if (DBG) log("cleanUpConnection: reason: " + reason); @@ -381,7 +297,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { // Clear the reconnect alarm, if set. if (mReconnectIntent != null) { AlarmManager am = - (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); + (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); am.cancel(mReconnectIntent); mReconnectIntent = null; } @@ -390,11 +306,12 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { notifyDataAvailability(reason); boolean notificationDeferred = false; - for (DataConnection conn : dataConnectionList) { + for (DataConnection conn : mDataConnections.values()) { if(conn != null) { if (tearDown) { if (DBG) log("cleanUpConnection: teardown, call conn.disconnect"); - conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, reason)); + conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, + conn.getDataConnectionId(), 0, reason)); notificationDeferred = true; } else { if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously"); @@ -413,10 +330,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } private CdmaDataConnection findFreeDataConnection() { - for (DataConnection connBase : dataConnectionList) { - CdmaDataConnection conn = (CdmaDataConnection) connBase; - if (conn.isInactive()) { - return conn; + for (DataConnection dc : mDataConnections.values()) { + if (dc.isInactive()) { + return (CdmaDataConnection) dc; } } return null; @@ -430,7 +346,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { return false; } - mActiveDataConnection = conn; + /** TODO: We probably want the connection being setup to a parameter passed around */ + mPendingDataConnection = conn; String[] types; if (mRequestedApnType.equals(Phone.APN_TYPE_DUN)) { types = new String[1]; @@ -458,28 +375,31 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } private void resetPollStats() { - txPkts = -1; - rxPkts = -1; - sentSinceLastRecv = 0; - netStatPollPeriod = POLL_NETSTAT_MILLIS; + mTxPkts = -1; + mRxPkts = -1; + mSentSinceLastRecv = 0; + mNetStatPollPeriod = POLL_NETSTAT_MILLIS; mNoRecvPollCount = 0; } + @Override protected void startNetStatPoll() { - if (state == State.CONNECTED && netStatPollEnabled == false) { - Log.d(LOG_TAG, "[DataConnection] Start poll NetStat"); + if (mState == State.CONNECTED && mNetStatPollEnabled == false) { + log("[DataConnection] Start poll NetStat"); resetPollStats(); - netStatPollEnabled = true; + mNetStatPollEnabled = true; mPollNetStat.run(); } } + @Override protected void stopNetStatPoll() { - netStatPollEnabled = false; + mNetStatPollEnabled = false; removeCallbacks(mPollNetStat); - Log.d(LOG_TAG, "[DataConnection] Stop poll NetStat"); + log("[DataConnection] Stop poll NetStat"); } + @Override protected void restartRadio() { if (DBG) log("Cleanup connection and wait " + (TIME_DELAYED_TO_RESTART_RADIO / 1000) + "s to restart radio"); @@ -496,73 +416,73 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { Activity newActivity; - preTxPkts = txPkts; - preRxPkts = rxPkts; + preTxPkts = mTxPkts; + preRxPkts = mRxPkts; - txPkts = TrafficStats.getMobileTxPackets(); - rxPkts = TrafficStats.getMobileRxPackets(); + mTxPkts = TrafficStats.getMobileTxPackets(); + mRxPkts = TrafficStats.getMobileRxPackets(); - //Log.d(LOG_TAG, "rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); + //log("rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); - if (netStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { - sent = txPkts - preTxPkts; - received = rxPkts - preRxPkts; + if (mNetStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { + sent = mTxPkts - preTxPkts; + received = mRxPkts - preRxPkts; if ( sent > 0 && received > 0 ) { - sentSinceLastRecv = 0; + mSentSinceLastRecv = 0; newActivity = Activity.DATAINANDOUT; } else if (sent > 0 && received == 0) { - if (phone.getState() == Phone.State.IDLE) { - sentSinceLastRecv += sent; + if (mPhone.getState() == Phone.State.IDLE) { + mSentSinceLastRecv += sent; } else { - sentSinceLastRecv = 0; + mSentSinceLastRecv = 0; } newActivity = Activity.DATAOUT; } else if (sent == 0 && received > 0) { - sentSinceLastRecv = 0; + mSentSinceLastRecv = 0; newActivity = Activity.DATAIN; } else if (sent == 0 && received == 0) { - newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE; + newActivity = (mActivity == Activity.DORMANT) ? mActivity : Activity.NONE; } else { - sentSinceLastRecv = 0; - newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE; + mSentSinceLastRecv = 0; + newActivity = (mActivity == Activity.DORMANT) ? mActivity : Activity.NONE; } - if (activity != newActivity) { - activity = newActivity; - phone.notifyDataActivity(); + if (mActivity != newActivity && mIsScreenOn) { + mActivity = newActivity; + mPhone.notifyDataActivity(); } } - if (sentSinceLastRecv >= NUMBER_SENT_PACKETS_OF_HANG) { + if (mSentSinceLastRecv >= NUMBER_SENT_PACKETS_OF_HANG) { // Packets sent without ack exceeded threshold. if (mNoRecvPollCount == 0) { EventLog.writeEvent( EventLogTags.PDP_RADIO_RESET_COUNTDOWN_TRIGGERED, - sentSinceLastRecv); + mSentSinceLastRecv); } if (mNoRecvPollCount < NO_RECV_POLL_LIMIT) { mNoRecvPollCount++; // Slow down the poll interval to let things happen - netStatPollPeriod = POLL_NETSTAT_SLOW_MILLIS; + mNetStatPollPeriod = POLL_NETSTAT_SLOW_MILLIS; } else { - if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) + + if (DBG) log("Sent " + String.valueOf(mSentSinceLastRecv) + " pkts since last received"); // We've exceeded the threshold. Restart the radio. - netStatPollEnabled = false; + mNetStatPollEnabled = false; stopNetStatPoll(); restartRadio(); EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, NO_RECV_POLL_LIMIT); } } else { mNoRecvPollCount = 0; - netStatPollPeriod = POLL_NETSTAT_MILLIS; + mNetStatPollPeriod = POLL_NETSTAT_MILLIS; } - if (netStatPollEnabled) { - mDataConnectionTracker.postDelayed(this, netStatPollPeriod); + if (mNetStatPollEnabled) { + mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod); } } }; @@ -594,7 +514,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) { - if (state == State.FAILED) { + if (mState == State.FAILED) { /** * For now With CDMA we never try to reconnect on * error and instead just continue to retry @@ -602,15 +522,15 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { * TODO: Make this configurable? */ int nextReconnectDelay = mRetryMgr.getRetryTimer(); - Log.d(LOG_TAG, "Data Connection activate failed. Scheduling next attempt for " + log("Data Connection activate failed. Scheduling next attempt for " + (nextReconnectDelay / 1000) + "s"); AlarmManager am = - (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); + (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(INTENT_RECONNECT_ALARM); intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, reason); mReconnectIntent = PendingIntent.getBroadcast( - phone.getContext(), 0, intent, 0); + mPhone.getContext(), 0, intent, 0); am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + nextReconnectDelay, mReconnectIntent); @@ -618,7 +538,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { mRetryMgr.increaseRetryCount(); if (!shouldPostNotification(lastFailCauseCode)) { - Log.d(LOG_TAG,"NOT Posting Data Connection Unavailable notification " + log("NOT Posting Data Connection Unavailable notification " + "-- likely transient error"); } else { notifyNoData(lastFailCauseCode); @@ -639,14 +559,14 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } protected void onRecordsLoaded() { - if (state == State.FAILED) { + if (mState == State.FAILED) { cleanUpConnection(false, null); } sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED)); } protected void onNVReady() { - if (state == State.FAILED) { + if (mState == State.FAILED) { cleanUpConnection(false, null); } sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); @@ -657,12 +577,13 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { */ @Override protected void onEnableNewApn() { - cleanUpConnection(true, Phone.REASON_APN_SWITCHED); + cleanUpConnection(true, Phone.REASON_APN_SWITCHED); } /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected boolean onTrySetupData(String reason) { return trySetupData(reason); } @@ -670,6 +591,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected void onRoamingOff() { trySetupData(Phone.REASON_ROAMING_OFF); } @@ -677,6 +599,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected void onRoamingOn() { if (getDataOnRoamingEnabled()) { trySetupData(Phone.REASON_ROAMING_ON); @@ -689,19 +612,20 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected void onRadioAvailable() { - if (phone.getSimulatedRadioControl() != null) { + if (mPhone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator // FIXME this can be improved setState(State.CONNECTED); notifyDataConnection(null); - Log.i(LOG_TAG, "We're on the simulator; assuming data is connected"); + log("We're on the simulator; assuming data is connected"); } notifyDataAvailability(null); - if (state != State.IDLE) { + if (mState != State.IDLE) { cleanUpConnection(true, null); } } @@ -709,13 +633,14 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected void onRadioOffOrNotAvailable() { mRetryMgr.resetRetryCount(); - if (phone.getSimulatedRadioControl() != null) { + if (mPhone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator // FIXME this can be improved - Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless"); + log("We're on the simulator; assuming radio off is meaningless"); } else { if (DBG) log("Radio is off and clean up all connection"); cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF); @@ -725,6 +650,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected void onDataSetupComplete(AsyncResult ar) { String reason = null; if (ar.userObj instanceof String) { @@ -733,8 +659,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { if (ar.exception == null) { // TODO: We should clear LinkProperties/Capabilities when torn down or disconnected - mLinkProperties = getLinkProperties(mActiveDataConnection); - mLinkCapabilities = getLinkCapabilities(mActiveDataConnection); + mLinkProperties = getLinkProperties(mPendingDataConnection); + mLinkCapabilities = getLinkCapabilities(mPendingDataConnection); // everything is setup notifyDefaultData(reason); @@ -754,8 +680,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * Called when EVENT_DISCONNECT_DONE is received. */ - protected void onDisconnectDone(AsyncResult ar) { - if(DBG) log("EVENT_DISCONNECT_DONE"); + @Override + protected void onDisconnectDone(int connId, AsyncResult ar) { + if(DBG) log("EVENT_DISCONNECT_DONE connId=" + connId); String reason = null; if (ar.userObj instanceof String) { reason = (String) ar.userObj; @@ -799,8 +726,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected void onVoiceCallStarted() { - if (state == State.CONNECTED && !mCdmaPhone.mSST.isConcurrentVoiceAndData()) { + if (mState == State.CONNECTED && !mCdmaPhone.mSST.isConcurrentVoiceAndData()) { stopNetStatPoll(); notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); notifyDataAvailability(Phone.REASON_VOICE_CALL_STARTED); @@ -810,8 +738,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected void onVoiceCallEnded() { - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { if (!mCdmaPhone.mSST.isConcurrentVoiceAndData()) { startNetStatPoll(); notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); @@ -827,39 +756,49 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } } - /** - * @override com.android.internal.telephony.DataConnectionTracker - */ + @Override protected void onCleanUpConnection(boolean tearDown, String reason) { cleanUpConnection(tearDown, reason); } private void createAllDataConnectionList() { - dataConnectionList = new ArrayList<DataConnection>(); CdmaDataConnection dataConn; - for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) { - dataConn = CdmaDataConnection.makeDataConnection(mCdmaPhone); - dataConnectionList.add(dataConn); - } + /** TODO: Use one retry manager for all connections for now */ + RetryManager rm = mRetryMgr; + if (!rm.configure(SystemProperties.get("ro.cdma.data_retry_config"))) { + if (!rm.configure(DEFAULT_DATA_RETRY_CONFIG)) { + // Should never happen, log an error and default to a simple linear sequence. + log("Could not configure using DEFAULT_DATA_RETRY_CONFIG=" + + DEFAULT_DATA_RETRY_CONFIG); + rm.configure(20, 2000, 1000); + } + } + + for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) { + int id = mUniqueIdGenerator.getAndIncrement(); + + dataConn = CdmaDataConnection.makeDataConnection(mCdmaPhone, id, rm); + mDataConnections.put(id, dataConn); + } } private void destroyAllDataConnectionList() { - if(dataConnectionList != null) { - dataConnectionList.removeAll(dataConnectionList); + if(mDataConnections != null) { + mDataConnections.clear(); } } private void onCdmaDataDetached() { - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { startNetStatPoll(); notifyDataConnection(Phone.REASON_CDMA_DATA_DETACHED); } else { - if (state == State.FAILED) { + if (mState == State.FAILED) { cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED); mRetryMgr.resetRetryCount(); - CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation()); + CdmaCellLocation loc = (CdmaCellLocation)(mPhone.getCellLocation()); EventLog.writeEvent(EventLogTags.CDMA_DATA_SETUP_FAILED, loc != null ? loc.getBaseStationId() : -1, TelephonyManager.getDefault().getNetworkType()); @@ -886,8 +825,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { private void onRestartRadio() { if (mPendingRestartRadio) { - Log.d(LOG_TAG, "************TURN OFF RADIO**************"); - phone.mCM.setRadioPower(false, null); + log("************TURN OFF RADIO**************"); + mPhone.mCM.setRadioPower(false, null); /* Note: no need to call setRadioPower(true). Assuming the desired * radio power state is still ON (as tracked by ServiceStateTracker), * ServiceStateTracker will call setRadioPower when it receives the @@ -900,7 +839,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } private void writeEventLogCdmaDataDrop() { - CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation()); + CdmaCellLocation loc = (CdmaCellLocation)(mPhone.getCellLocation()); EventLog.writeEvent(EventLogTags.CDMA_DATA_DROP, loc != null ? loc.getBaseStationId() : -1, TelephonyManager.getDefault().getNetworkType()); @@ -916,7 +855,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { return; } - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { boolean isActiveOrDormantConnectionPresent = false; int connectionState = DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE; @@ -932,7 +871,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { if (!isActiveOrDormantConnectionPresent) { // No active or dormant connection - Log.i(LOG_TAG, "onDataStateChanged: No active connection" + log("onDataStateChanged: No active connection" + "state is CONNECTED, disconnecting/cleanup"); writeEventLogCdmaDataDrop(); cleanUpConnection(true, null); @@ -941,42 +880,39 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { switch (connectionState) { case DATA_CONNECTION_ACTIVE_PH_LINK_UP: - Log.v(LOG_TAG, "onDataStateChanged: active=LINK_ACTIVE && CONNECTED, ignore"); - activity = Activity.NONE; - phone.notifyDataActivity(); + log("onDataStateChanged: active=LINK_ACTIVE && CONNECTED, ignore"); + mActivity = Activity.NONE; + mPhone.notifyDataActivity(); startNetStatPoll(); break; case DATA_CONNECTION_ACTIVE_PH_LINK_DOWN: - Log.v(LOG_TAG, "onDataStateChanged active=LINK_DOWN && CONNECTED, dormant"); - activity = Activity.DORMANT; - phone.notifyDataActivity(); + log("onDataStateChanged active=LINK_DOWN && CONNECTED, dormant"); + mActivity = Activity.DORMANT; + mPhone.notifyDataActivity(); stopNetStatPoll(); break; default: - Log.v(LOG_TAG, "onDataStateChanged: IGNORE unexpected DataCallState.active=" + log("onDataStateChanged: IGNORE unexpected DataCallState.active=" + connectionState); } } else { // TODO: Do we need to do anything? - Log.i(LOG_TAG, "onDataStateChanged: not connected, state=" + state + " ignoring"); + log("onDataStateChanged: not connected, state=" + mState + " ignoring"); } } - public ArrayList<DataConnection> getAllDataConnections() { - return dataConnectionList; - } - private void startDelayedRetry(FailCause cause, String reason) { notifyNoData(cause); reconnectAfterFail(cause, reason); } + @Override public void handleMessage (Message msg) { - if (!phone.mIsTheCurrentActivePhone) { - Log.d(LOG_TAG, "Ignore CDMA msgs since CDMA phone is inactive"); + if (!mPhone.mIsTheCurrentActivePhone) { + log("Ignore CDMA msgs since CDMA phone is inactive"); return; } @@ -1013,7 +949,13 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } } + @Override protected void log(String s) { Log.d(LOG_TAG, "[CdmaDataConnectionTracker] " + s); } + + @Override + protected void loge(String s) { + Log.e(LOG_TAG, "[CdmaDataConnectionTracker] " + s); + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java index 1572f09..d428099 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java @@ -23,6 +23,7 @@ import android.util.Patterns; import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.Phone; import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.RetryManager; /** * {@hide} @@ -53,23 +54,27 @@ public class GsmDataConnection extends DataConnection { private ApnSetting apn; //***** Constructor - private GsmDataConnection(GSMPhone phone, String name) { - super(phone, name); + private GsmDataConnection(GSMPhone phone, String name, RetryManager rm) { + super(phone, name, rm); } /** * Create the connection object * - * @param phone + * @param phone the Phone + * @param id the connection id + * @param rm the RetryManager * @return GsmDataConnection that was created. */ - static GsmDataConnection makeDataConnection(GSMPhone phone) { + static GsmDataConnection makeDataConnection(GSMPhone phone, int id, RetryManager rm) { synchronized (mCountLock) { mCount += 1; } - GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDataConnection-" + mCount); + GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDataConnection-" + mCount, rm); gsmDc.start(); if (DBG) gsmDc.log("Made " + gsmDc.getName()); + gsmDc.mId = id; + gsmDc.mRetryMgr = rm; return gsmDc; } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index 66da6e8..2aca9ad 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -18,27 +18,19 @@ package com.android.internal.telephony.gsm; import android.app.AlarmManager; import android.app.PendingIntent; -import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; import android.database.ContentObserver; import android.database.Cursor; -import android.net.IConnectivityManager; -import android.net.NetworkInfo; import android.net.ProxyProperties; import android.net.TrafficStats; import android.net.Uri; -import android.net.wifi.WifiManager; import android.os.AsyncResult; import android.os.Message; -import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; -import android.preference.PreferenceManager; import android.provider.Settings; import android.provider.Telephony; import android.telephony.ServiceState; @@ -61,6 +53,7 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.HashMap; /** * {@hide} @@ -85,9 +78,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { //***** Instance Variables - // Indicates baseband will not auto-attach - private boolean noAutoAttach = false; - private boolean mReregisterOnReconnectFailure = false; private ContentResolver mResolver; @@ -95,13 +85,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // Count of PDP reset attempts; reset when we see incoming, // call reRegisterNetwork, or pingTest succeeds. private int mPdpResetCount = 0; - private boolean mIsScreenOn = true; /** Delay between APN attempts */ protected static final int APN_DELAY_MILLIS = 5000; //useful for debugging - boolean failNextConnect = false; + boolean mFailNextConnect = false; /** * allApns holds all apns for this sim spn, retrieved from @@ -109,104 +98,49 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * * Create once after simcard info is loaded */ - private ArrayList<ApnSetting> allApns = null; + private ArrayList<ApnSetting> mAllApns = null; /** * waitingApns holds all apns that are waiting to be connected * * It is a subset of allApns and has the same format */ - private ArrayList<ApnSetting> waitingApns = null; + private ArrayList<ApnSetting> mWaitingApns = null; - private ApnSetting preferredApn = null; + private ApnSetting mPreferredApn = null; /* Currently active APN */ protected ApnSetting mActiveApn; - /** - * pdpList holds all the PDP connection, i.e. IP Link in GPRS - */ - private ArrayList<DataConnection> pdpList; + /** The DataConnection being setup */ + private GsmDataConnection mPendingDataConnection; - /** Currently active DataConnection */ - private GsmDataConnection mActivePdp; + /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */ + private HashMap<String, Integer> mApnToDataConnectionId = + new HashMap<String, Integer>(); /** Is packet service restricted by network */ private boolean mIsPsRestricted = false; //***** Constants - // TODO: Increase this to match the max number of simultaneous - // PDP contexts we plan to support. - /** - * Pool size of DataConnection objects. - */ - private static final int PDP_CONNECTION_POOL_SIZE = 1; - private static final int POLL_PDP_MILLIS = 5 * 1000; private static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.gprs-reconnect"; - private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason"; static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn"); static final String APN_ID = "apn_id"; private boolean canSetPreferApn = false; - // for tracking retries on the default APN - private RetryManager mDefaultRetryManager; - // for tracking retries on a secondary APN - private RetryManager mSecondaryRetryManager; - - BroadcastReceiver mIntentReceiver = new BroadcastReceiver () - { - @Override - public void onReceive(Context context, Intent intent) - { - String action = intent.getAction(); - if (action.equals(Intent.ACTION_SCREEN_ON)) { - mIsScreenOn = true; - stopNetStatPoll(); - startNetStatPoll(); - } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { - mIsScreenOn = false; - stopNetStatPoll(); - startNetStatPoll(); - } else if (action.equals((INTENT_RECONNECT_ALARM))) { - Log.d(LOG_TAG, "GPRS reconnect alarm. Previous state was " + state); - - String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON); - if (state == State.FAILED) { - Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); - msg.arg1 = 0; // tearDown is false - msg.obj = (String) reason; - sendMessage(msg); - } - sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); - } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - final android.net.NetworkInfo networkInfo = (NetworkInfo) - intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); - mIsWifiConnected = (networkInfo != null && networkInfo.isConnected()); - } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; - - if (!enabled) { - // when wifi got disabled, the NETWORK_STATE_CHANGED_ACTION - // quit and won't report disconnected til next enabling. - mIsWifiConnected = false; - } - } - } - }; - /** Watches for changes to the APN db. */ - private ApnChangeObserver apnObserver; + private ApnChangeObserver mApnObserver; //***** Constructor GsmDataConnectionTracker(GSMPhone p) { super(p); mGsmPhone = p; + p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); p.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); @@ -220,73 +154,26 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { p.mSST.registerForPsRestrictedEnabled(this, EVENT_PS_RESTRICT_ENABLED, null); p.mSST.registerForPsRestrictedDisabled(this, EVENT_PS_RESTRICT_DISABLED, null); - IntentFilter filter = new IntentFilter(); - filter.addAction(INTENT_RECONNECT_ALARM); - filter.addAction(Intent.ACTION_SCREEN_ON); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - - // TODO: Why is this registering the phone as the receiver of the intent - // and not its own handler? - p.getContext().registerReceiver(mIntentReceiver, filter, null, p); - - mDataConnectionTracker = this; - mResolver = phone.getContext().getContentResolver(); + mResolver = mPhone.getContext().getContentResolver(); - apnObserver = new ApnChangeObserver(); + mApnObserver = new ApnChangeObserver(); p.getContext().getContentResolver().registerContentObserver( - Telephony.Carriers.CONTENT_URI, true, apnObserver); + Telephony.Carriers.CONTENT_URI, true, mApnObserver); - createAllPdpList(); - - // This preference tells us 1) initial condition for "dataEnabled", - // and 2) whether the RIL will setup the baseband to auto-PS attach. - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext()); - boolean dataEnabledSetting = true; - try { - dataEnabledSetting = IConnectivityManager.Stub.asInterface(ServiceManager. - getService(Context.CONNECTIVITY_SERVICE)).getMobileDataEnabled(); - } catch (Exception e) { - // nothing to do - use the old behavior and leave data on - } - dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false) && - dataEnabledSetting; - if (dataEnabled[APN_DEFAULT_ID]) { - enabledCount++; - } - noAutoAttach = !dataEnabled[APN_DEFAULT_ID]; - - if (!mRetryMgr.configure(SystemProperties.get("ro.gsm.data_retry_config"))) { - if (!mRetryMgr.configure(DEFAULT_DATA_RETRY_CONFIG)) { - // Should never happen, log an error and default to a simple linear sequence. - Log.e(LOG_TAG, "Could not configure using DEFAULT_DATA_RETRY_CONFIG=" - + DEFAULT_DATA_RETRY_CONFIG); - mRetryMgr.configure(20, 2000, 1000); - } - } - - mDefaultRetryManager = mRetryMgr; - mSecondaryRetryManager = new RetryManager(); - - if (!mSecondaryRetryManager.configure(SystemProperties.get( - "ro.gsm.2nd_data_retry_config"))) { - if (!mSecondaryRetryManager.configure(SECONDARY_DATA_RETRY_CONFIG)) { - // Should never happen, log an error and default to a simple sequence. - Log.e(LOG_TAG, "Could note configure using SECONDARY_DATA_RETRY_CONFIG=" - + SECONDARY_DATA_RETRY_CONFIG); - mSecondaryRetryManager.configure("max_retries=3, 333, 333, 333"); - } - } + /** Create the default connection */ + createDataConnection(Phone.APN_TYPE_DEFAULT); } + @Override public void dispose() { + super.dispose(); + //Unregister for all events - phone.mCM.unregisterForAvailable(this); - phone.mCM.unregisterForOffOrNotAvailable(this); + mPhone.mCM.unregisterForAvailable(this); + mPhone.mCM.unregisterForOffOrNotAvailable(this); mGsmPhone.mSIMRecords.unregisterForRecordsLoaded(this); - phone.mCM.unregisterForDataStateChanged(this); + mPhone.mCM.unregisterForDataStateChanged(this); mGsmPhone.mCT.unregisterForVoiceCallEnded(this); mGsmPhone.mCT.unregisterForVoiceCallStarted(this); mGsmPhone.mSST.unregisterForGprsAttached(this); @@ -296,29 +183,36 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { mGsmPhone.mSST.unregisterForPsRestrictedEnabled(this); mGsmPhone.mSST.unregisterForPsRestrictedDisabled(this); - phone.getContext().unregisterReceiver(this.mIntentReceiver); - phone.getContext().getContentResolver().unregisterContentObserver(this.apnObserver); + mPhone.getContext().getContentResolver().unregisterContentObserver(this.mApnObserver); - destroyAllPdpList(); + destroyDataConnections(); } + @Override protected void finalize() { - if(DBG) Log.d(LOG_TAG, "GsmDataConnectionTracker finalized"); + if(DBG) log("finalize"); + } + + @Override + protected String getActionIntentReconnectAlarm() { + return INTENT_RECONNECT_ALARM; } + @Override protected void setState(State s) { if (DBG) log ("setState: " + s); - if (state != s) { - EventLog.writeEvent(EventLogTags.GSM_DATA_STATE_CHANGE, state.toString(), s.toString()); - state = s; + if (mState != s) { + EventLog.writeEvent(EventLogTags.GSM_DATA_STATE_CHANGE, mState.toString(), s.toString()); + mState = s; } - if (state == State.FAILED) { - if (waitingApns != null) - waitingApns.clear(); // when teardown the connection and set to IDLE + if (mState == State.FAILED) { + if (mWaitingApns != null) + mWaitingApns.clear(); // when tear down the connection and set to IDLE } } + @Override public String[] getActiveApnTypes() { String[] result; if (mActiveApn != null) { @@ -330,6 +224,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return result; } + @Override protected String getActiveApnString() { String result = null; if (mActiveApn != null) { @@ -347,15 +242,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * * @return false while no data connection if all above requirements are met. */ + @Override public boolean isDataConnectionAsDesired() { - boolean roaming = phone.getServiceState().getRoaming(); + boolean roaming = mPhone.getServiceState().getRoaming(); if (mGsmPhone.mSIMRecords.getRecordsLoaded() && mGsmPhone.mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE && (!roaming || getDataOnRoamingEnabled()) && !mIsWifiConnected && !mIsPsRestricted ) { - return (state == State.CONNECTED); + return (mState == State.CONNECTED); } return true; } @@ -372,8 +268,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return (fetchDunApn() != null); } - if (allApns != null) { - for (ApnSetting apn : allApns) { + if (mAllApns != null) { + for (ApnSetting apn : mAllApns) { if (apn.canHandleType(type)) { return true; } @@ -382,14 +278,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return false; } - /** - * Formerly this method was ArrayList<GsmDataConnection> getAllPdps() - */ - public ArrayList<DataConnection> getAllDataConnections() { - ArrayList<DataConnection> pdps = (ArrayList<DataConnection>)pdpList.clone(); - return pdps; - } - //****** Called from ServiceStateTracker /** * Invoked when ServiceStateTracker observes a transition from GPRS @@ -405,11 +293,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } private void onGprsAttached() { - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { startNetStatPoll(); notifyDataConnection(Phone.REASON_GPRS_ATTACHED); } else { - if (state == State.FAILED) { + if (mState == State.FAILED) { cleanUpConnection(false, Phone.REASON_GPRS_ATTACHED); mRetryMgr.resetRetryCount(); } @@ -417,26 +305,30 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } + @Override protected boolean isDataAllowed() { int gprsState = mGsmPhone.mSST.getCurrentGprsState(); boolean desiredPowerState = mGsmPhone.mSST.getDesiredPowerState(); - boolean allowed = ((gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach) && - mGsmPhone.mSIMRecords.getRecordsLoaded() && - phone.getState() == Phone.State.IDLE && - mMasterDataEnabled && - (!phone.getServiceState().getRoaming() || getDataOnRoamingEnabled()) && - !mIsPsRestricted && - desiredPowerState); + boolean allowed = + (gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) && + mGsmPhone.mSIMRecords.getRecordsLoaded() && + mPhone.getState() == Phone.State.IDLE && + mMasterDataEnabled && + (!mPhone.getServiceState().getRoaming() || getDataOnRoamingEnabled()) && + !mIsPsRestricted && + desiredPowerState; if (!allowed && DBG) { String reason = ""; - if (gprsState != ServiceState.STATE_IN_SERVICE) reason += " - gprs= " + gprsState; + if (!((gprsState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) { + reason += " - gprs= " + gprsState; + } if (!mGsmPhone.mSIMRecords.getRecordsLoaded()) reason += " - SIM not loaded"; - if (phone.getState() != Phone.State.IDLE) { - reason += " - PhoneState= " + phone.getState(); + if (mPhone.getState() != Phone.State.IDLE) { + reason += " - PhoneState= " + mPhone.getState(); } if (!mMasterDataEnabled) reason += " - mMasterDataEnabled= false"; - if (phone.getServiceState().getRoaming() && getDataOnRoamingEnabled()) { + if (mPhone.getServiceState().getRoaming() && getDataOnRoamingEnabled()) { reason += " - Roaming"; } if (mIsPsRestricted) reason += " - mIsPsRestricted= true"; @@ -449,38 +341,38 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private boolean trySetupData(String reason) { if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason)); - Log.d(LOG_TAG, "[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted); + log("[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted); - if (phone.getSimulatedRadioControl() != null) { + if (mPhone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator // FIXME this can be improved setState(State.CONNECTED); notifyDataConnection(reason); - Log.i(LOG_TAG, "(fix?) We're on the simulator; assuming data is connected"); + log("(fix?) We're on the simulator; assuming data is connected"); return true; } int gprsState = mGsmPhone.mSST.getCurrentGprsState(); boolean desiredPowerState = mGsmPhone.mSST.getDesiredPowerState(); - if (((state == State.IDLE) || (state == State.SCANNING)) && + if (((mState == State.IDLE) || (mState == State.SCANNING)) && isDataAllowed() && getAnyDataEnabled()) { - if (state == State.IDLE) { - waitingApns = buildWaitingApns(); - if (waitingApns.isEmpty()) { + if (mState == State.IDLE) { + mWaitingApns = buildWaitingApns(mRequestedApnType); + if (mWaitingApns.isEmpty()) { if (DBG) log("No APN found"); notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN); notifyOffApnsOfAvailability(reason, false); return false; } else { - log ("Create from allApns : " + apnListToString(allApns)); + log ("Create from allApns : " + apnListToString(mAllApns)); } } if (DBG) { - log ("Setup waitngApns : " + apnListToString(waitingApns)); + log ("Setup waitngApns : " + apnListToString(mWaitingApns)); } boolean retValue = setupData(reason); notifyOffApnsOfAvailability(reason, retValue); @@ -492,13 +384,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } /** - * If tearDown is true, this only tears down a CONNECTED session. Presently, - * there is no mechanism for abandoning an INITING/CONNECTING session, - * but would likely involve cancelling pending async requests or - * setting a flag or new state to ignore them when they came in - * @param tearDown true if the underlying GsmDataConnection should be - * disconnected. - * @param reason reason for the clean up. + * Cleanup all connections. + * + * TODO: Cleanup only a specified connection passed as a parameter. + * + * @param tearDown true if the underlying DataConnection should be disconnected. + * @param reason for the clean up. */ private void cleanUpConnection(boolean tearDown, String reason) { if (DBG) log("Clean up connection due to " + reason); @@ -506,7 +397,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // Clear the reconnect alarm, if set. if (mReconnectIntent != null) { AlarmManager am = - (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); + (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); am.cancel(mReconnectIntent); mReconnectIntent = null; } @@ -514,10 +405,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { setState(State.DISCONNECTING); boolean notificationDeferred = false; - for (DataConnection conn : pdpList) { + for (DataConnection conn : mDataConnections.values()) { if (tearDown) { if (DBG) log("cleanUpConnection: teardown, call conn.disconnect"); - conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, reason)); + conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, + conn.getDataConnectionId(), 0, reason)); notificationDeferred = true; } else { if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously"); @@ -575,51 +467,49 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return result; } - private GsmDataConnection findFreePdp() { - for (DataConnection conn : pdpList) { - GsmDataConnection pdp = (GsmDataConnection) conn; - if (pdp.isInactive()) { - return pdp; + private GsmDataConnection findFreeDataConnection() { + for (DataConnection dc : mDataConnections.values()) { + if (dc.isInactive()) { + log("found free GsmDataConnection"); + return (GsmDataConnection) dc; } } + log("NO free GsmDataConnection"); return null; } private boolean setupData(String reason) { ApnSetting apn; - GsmDataConnection pdp; + GsmDataConnection gdc; apn = getNextApn(); if (apn == null) return false; - pdp = findFreePdp(); - if (pdp == null) { + gdc = findFreeDataConnection(); + if (gdc == null) { if (DBG) log("setupData: No free GsmDataConnection found!"); return false; } mActiveApn = apn; - mActivePdp = pdp; + mPendingDataConnection = gdc; Message msg = obtainMessage(); msg.what = EVENT_DATA_SETUP_COMPLETE; msg.obj = reason; - pdp.connect(msg, apn); + gdc.connect(msg, apn); setState(State.INITING); notifyDataConnection(reason); return true; } - private boolean - pdpStatesHasCID (ArrayList<DataCallState> states, int cid) { + private boolean dataCallStatesHasCID (ArrayList<DataCallState> states, int cid) { for (int i = 0, s = states.size() ; i < s ; i++) { if (states.get(i).cid == cid) return true; } - return false; } - private boolean - pdpStatesHasActiveCID (ArrayList<DataCallState> states, int cid) { + private boolean dataCallStatesHasActiveCID (ArrayList<DataCallState> states, int cid) { for (int i = 0, s = states.size() ; i < s ; i++) { if ((states.get(i).cid == cid) && (states.get(i).active != 0)) { return true; @@ -635,7 +525,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private void onApnChanged() { boolean isConnected; - isConnected = (state != State.IDLE && state != State.FAILED); + isConnected = (mState != State.IDLE && mState != State.FAILED); // The "current" may no longer be valid. MMS depends on this to send properly. mGsmPhone.updateCurrentCarrierInProvider(); @@ -643,7 +533,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // TODO: It'd be nice to only do this if the changed entrie(s) // match the current operator. createAllApnList(); - if (state != State.DISCONNECTING) { + if (mState != State.DISCONNECTING) { cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED); if (!isConnected) { // reset reconnect timer @@ -660,10 +550,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * via an unsolicited response (which could have happened at any * previous state */ - protected void onPdpStateChanged (AsyncResult ar, boolean explicitPoll) { - ArrayList<DataCallState> pdpStates; + private void onDataStateChanged (AsyncResult ar, boolean explicitPoll) { + ArrayList<DataCallState> dataCallStates; - pdpStates = (ArrayList<DataCallState>)(ar.result); + dataCallStates = (ArrayList<DataCallState>)(ar.result); if (ar.exception != null) { // This is probably "radio not available" or something @@ -672,42 +562,42 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return; } - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { // The way things are supposed to work, the PDP list // should not contain the CID after it disconnects. // However, the way things really work, sometimes the PDP // context is still listed with active = false, which // makes it hard to distinguish an activating context from // an activated-and-then deactivated one. - if (!pdpStatesHasCID(pdpStates, cidActive)) { + if (!dataCallStatesHasCID(dataCallStates, mCidActive)) { // It looks like the PDP context has deactivated. // Tear everything down and try to reconnect. - Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting"); + log("PDP connection has dropped. Reconnecting"); // Add an event log when the network drops PDP - GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); + GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation()); EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, loc != null ? loc.getCid() : -1, TelephonyManager.getDefault().getNetworkType()); cleanUpConnection(true, null); return; - } else if (!pdpStatesHasActiveCID(pdpStates, cidActive)) { + } else if (!dataCallStatesHasActiveCID(dataCallStates, mCidActive)) { // Here, we only consider this authoritative if we asked for the // PDP list. If it was an unsolicited response, we poll again // to make sure everyone agrees on the initial state. if (!explicitPoll) { // We think it disconnected but aren't sure...poll from our side - phone.mCM.getPDPContextList( + mPhone.mCM.getPDPContextList( this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); } else { - Log.i(LOG_TAG, "PDP connection has dropped (active=false case). " + log("PDP connection has dropped (active=false case). " + " Reconnecting"); // Log the network drop on the event log. - GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); + GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation()); EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, loc != null ? loc.getCid() : -1, TelephonyManager.getDefault().getNetworkType()); @@ -734,38 +624,26 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { mActiveApn = null; } - /** - * This is a kludge to deal with the fact that - * the PDP state change notification doesn't always work - * with certain RIL impl's/basebands - * - */ - private void startPeriodicPdpPoll() { - removeMessages(EVENT_POLL_PDP); - - sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS); - } - private void resetPollStats() { - txPkts = -1; - rxPkts = -1; - sentSinceLastRecv = 0; - netStatPollPeriod = POLL_NETSTAT_MILLIS; + mTxPkts = -1; + mRxPkts = -1; + mSentSinceLastRecv = 0; + mNetStatPollPeriod = POLL_NETSTAT_MILLIS; mNoRecvPollCount = 0; } private void doRecovery() { - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { int maxPdpReset = Settings.Secure.getInt(mResolver, Settings.Secure.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT, DEFAULT_MAX_PDP_RESET_FAIL); if (mPdpResetCount < maxPdpReset) { mPdpResetCount++; - EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, sentSinceLastRecv); + EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, mSentSinceLastRecv); cleanUpConnection(true, Phone.REASON_PDP_RESET); } else { mPdpResetCount = 0; - EventLog.writeEvent(EventLogTags.PDP_REREGISTER_NETWORK, sentSinceLastRecv); + EventLog.writeEvent(EventLogTags.PDP_REREGISTER_NETWORK, mSentSinceLastRecv); mGsmPhone.mSST.reRegisterNetwork(null); } // TODO: Add increasingly drastic recovery steps, eg, @@ -773,23 +651,26 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } + @Override protected void startNetStatPoll() { - if (state == State.CONNECTED && mPingTestActive == false && netStatPollEnabled == false) { - Log.d(LOG_TAG, "[DataConnection] Start poll NetStat"); + if (mState == State.CONNECTED && mPingTestActive == false && mNetStatPollEnabled == false) { + log("[DataConnection] Start poll NetStat"); resetPollStats(); - netStatPollEnabled = true; + mNetStatPollEnabled = true; mPollNetStat.run(); } } + @Override protected void stopNetStatPoll() { - netStatPollEnabled = false; + mNetStatPollEnabled = false; removeCallbacks(mPollNetStat); - Log.d(LOG_TAG, "[DataConnection] Stop poll NetStat"); + log("[DataConnection] Stop poll NetStat"); } + @Override protected void restartRadio() { - Log.d(LOG_TAG, "************TURN OFF RADIO**************"); + log("************TURN OFF RADIO**************"); cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); mGsmPhone.mSST.powerOffRadioSafely(); /* Note: no need to call setRadioPower(true). Assuming the desired @@ -813,43 +694,43 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { Activity newActivity; - preTxPkts = txPkts; - preRxPkts = rxPkts; + preTxPkts = mTxPkts; + preRxPkts = mRxPkts; - txPkts = TrafficStats.getMobileTxPackets(); - rxPkts = TrafficStats.getMobileRxPackets(); + mTxPkts = TrafficStats.getMobileTxPackets(); + mRxPkts = TrafficStats.getMobileRxPackets(); - //Log.d(LOG_TAG, "rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); + //log("rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); - if (netStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { - sent = txPkts - preTxPkts; - received = rxPkts - preRxPkts; + if (mNetStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { + sent = mTxPkts - preTxPkts; + received = mRxPkts - preRxPkts; if ( sent > 0 && received > 0 ) { - sentSinceLastRecv = 0; + mSentSinceLastRecv = 0; newActivity = Activity.DATAINANDOUT; mPdpResetCount = 0; } else if (sent > 0 && received == 0) { - if (phone.getState() == Phone.State.IDLE) { - sentSinceLastRecv += sent; + if (mPhone.getState() == Phone.State.IDLE) { + mSentSinceLastRecv += sent; } else { - sentSinceLastRecv = 0; + mSentSinceLastRecv = 0; } newActivity = Activity.DATAOUT; } else if (sent == 0 && received > 0) { - sentSinceLastRecv = 0; + mSentSinceLastRecv = 0; newActivity = Activity.DATAIN; mPdpResetCount = 0; } else if (sent == 0 && received == 0) { newActivity = Activity.NONE; } else { - sentSinceLastRecv = 0; + mSentSinceLastRecv = 0; newActivity = Activity.NONE; } - if (activity != newActivity && mIsScreenOn) { - activity = newActivity; - phone.notifyDataActivity(); + if (mActivity != newActivity && mIsScreenOn) { + mActivity = newActivity; + mPhone.notifyDataActivity(); } } @@ -857,11 +738,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { Settings.Secure.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, NUMBER_SENT_PACKETS_OF_HANG); - if (sentSinceLastRecv >= watchdogTrigger) { + if (mSentSinceLastRecv >= watchdogTrigger) { // we already have NUMBER_SENT_PACKETS sent without ack if (mNoRecvPollCount == 0) { EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET_COUNTDOWN_TRIGGERED, - sentSinceLastRecv); + mSentSinceLastRecv); } int noRecvPollLimit = Settings.Secure.getInt(mResolver, @@ -871,21 +752,22 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // It's possible the PDP context went down and we weren't notified. // Start polling the context list in an attempt to recover. if (DBG) log("no DATAIN in a while; polling PDP"); - phone.mCM.getDataCallList(obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); + mPhone.mCM.getDataCallList(obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); mNoRecvPollCount++; // Slow down the poll interval to let things happen - netStatPollPeriod = Settings.Secure.getInt(mResolver, + mNetStatPollPeriod = Settings.Secure.getInt(mResolver, Settings.Secure.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS, POLL_NETSTAT_SLOW_MILLIS); } else { - if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) + + if (DBG) log("Sent " + String.valueOf(mSentSinceLastRecv) + " pkts since last received"); // We've exceeded the threshold. Run ping test as a final check; // it will proceed with recovery if ping fails. stopNetStatPoll(); Thread pingTest = new Thread() { + @Override public void run() { runPingTest(); } @@ -896,17 +778,17 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } else { mNoRecvPollCount = 0; if (mIsScreenOn) { - netStatPollPeriod = Settings.Secure.getInt(mResolver, + mNetStatPollPeriod = Settings.Secure.getInt(mResolver, Settings.Secure.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS); } else { - netStatPollPeriod = Settings.Secure.getInt(mResolver, + mNetStatPollPeriod = Settings.Secure.getInt(mResolver, Settings.Secure.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS, POLL_NETSTAT_SCREEN_OFF_MILLIS); } } - if (netStatPollEnabled) { - mDataConnectionTracker.postDelayed(this, netStatPollPeriod); + if (mNetStatPollEnabled) { + mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod); } } }; @@ -925,9 +807,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { status = p.waitFor(); } } catch (IOException e) { - Log.w(LOG_TAG, "ping failed: IOException"); + loge("ping failed: IOException"); } catch (Exception e) { - Log.w(LOG_TAG, "exception trying to ping"); + loge("exception trying to ping"); } if (status == 0) { @@ -968,7 +850,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) { - if (state == State.FAILED) { + if (mState == State.FAILED) { + /** TODO: Retrieve retry manager from connection itself */ if (!mRetryMgr.isRetryNeeded()) { if (!mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { // if no more retries on a secondary APN attempt, tell the world and revert. @@ -977,11 +860,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return; } if (mReregisterOnReconnectFailure) { - // We've re-registerd once now just retry forever. + // We've re-registered once now just retry forever. mRetryMgr.retryForeverUsingLastTimeout(); } else { // Try to re-register to the network. - Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network"); + log("PDP activate failed, Reregistering to the network"); mReregisterOnReconnectFailure = true; mGsmPhone.mSST.reRegisterNetwork(null); mRetryMgr.resetRetryCount(); @@ -990,15 +873,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } int nextReconnectDelay = mRetryMgr.getRetryTimer(); - Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for " + log("PDP activate failed. Scheduling next attempt for " + (nextReconnectDelay / 1000) + "s"); AlarmManager am = - (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); + (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(INTENT_RECONNECT_ALARM); intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, reason); mReconnectIntent = PendingIntent.getBroadcast( - phone.getContext(), 0, intent, 0); + mPhone.getContext(), 0, intent, 0); am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + nextReconnectDelay, mReconnectIntent); @@ -1006,7 +889,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { mRetryMgr.increaseRetryCount(); if (!shouldPostNotification(lastFailCauseCode)) { - Log.d(LOG_TAG,"NOT Posting GPRS Unavailable notification " + log("NOT Posting GPRS Unavailable notification " + "-- likely transient error"); } else { notifyNoData(lastFailCauseCode); @@ -1018,9 +901,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { setState(State.FAILED); } - protected void onRecordsLoaded() { + private void onRecordsLoaded() { createAllApnList(); - if (state == State.FAILED) { + if (mState == State.FAILED) { cleanUpConnection(false, null); } sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED)); @@ -1028,19 +911,29 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { @Override protected void onEnableNewApn() { + log("onEnableNewApn E"); // change our retry manager to use the appropriate numbers for the new APN if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { - mRetryMgr = mDefaultRetryManager; + log("onEnableNewApn default type"); + mRetryMgr = mPendingDataConnection.getRetryMgr(); + mRetryMgr.resetRetryCount(); + } else if (mApnToDataConnectionId.get(mRequestedApnType) == null) { + log("onEnableNewApn mRequestedApnType=" + mRequestedApnType + + " missing, make a new connection"); + int id = createDataConnection(mRequestedApnType); + mRetryMgr = mDataConnections.get(id).getRetryMgr(); + mRetryMgr.resetRetryCount(); } else { - mRetryMgr = mSecondaryRetryManager; + log("oneEnableNewApn connection already exists, nothing to setup"); } - mRetryMgr.resetRetryCount(); // TODO: To support simultaneous PDP contexts, this should really only call // cleanUpConnection if it needs to free up a GsmDataConnection. cleanUpConnection(true, Phone.REASON_APN_SWITCHED); + log("onEnableNewApn X"); } + @Override protected boolean onTrySetupData(String reason) { return trySetupData(reason); } @@ -1060,31 +953,33 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } + @Override protected void onRadioAvailable() { - if (phone.getSimulatedRadioControl() != null) { + if (mPhone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator // FIXME this can be improved setState(State.CONNECTED); notifyDataConnection(null); - Log.i(LOG_TAG, "We're on the simulator; assuming data is connected"); + log("We're on the simulator; assuming data is connected"); } - if (state != State.IDLE) { + if (mState != State.IDLE) { cleanUpConnection(true, null); } } + @Override protected void onRadioOffOrNotAvailable() { // Make sure our reconnect delay starts at the initial value // next time the radio comes on mRetryMgr.resetRetryCount(); mReregisterOnReconnectFailure = false; - if (phone.getSimulatedRadioControl() != null) { + if (mPhone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator // FIXME this can be improved - Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless"); + log("We're on the simulator; assuming radio off is meaningless"); } else { if (DBG) log("Radio is off and clean up all connection"); // TODO: Should we reset mRequestedApnType to "default"? @@ -1092,7 +987,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } + @Override protected void onDataSetupComplete(AsyncResult ar) { + /** TODO: Which connection is completing should be a parameter */ String reason = null; if (ar.userObj instanceof String) { reason = (String) ar.userObj; @@ -1100,10 +997,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (ar.exception == null) { // TODO: We should clear LinkProperties/Capabilities when torn down or disconnected - mLinkProperties = getLinkProperties(mActivePdp); - mLinkCapabilities = getLinkCapabilities(mActivePdp); + mLinkProperties = getLinkProperties(mPendingDataConnection); + mLinkCapabilities = getLinkCapabilities(mPendingDataConnection); - ApnSetting apn = mActivePdp.getApn(); + ApnSetting apn = mPendingDataConnection.getApn(); if (apn.proxy != null && apn.proxy.length() != 0) { try { ProxyProperties proxy = new ProxyProperties(); @@ -1111,11 +1008,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { Integer.parseInt(apn.port))); mLinkProperties.setHttpProxy(proxy); } catch (UnknownHostException e) { - Log.e(LOG_TAG, "UnknownHostException making ProxyProperties: " + e); + loge("UnknownHostException making ProxyProperties: " + e); } catch (SecurityException e) { - Log.e(LOG_TAG, "SecurityException making ProxyProperties: " + e); + loge("SecurityException making ProxyProperties: " + e); } catch (NumberFormatException e) { - Log.e(LOG_TAG, "NumberFormatException making ProxyProperties (" + apn.port + + loge("NumberFormatException making ProxyProperties (" + apn.port + "): " + e); } } @@ -1123,10 +1020,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // everything is setup if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { SystemProperties.set("gsm.defaultpdpcontext.active", "true"); - if (canSetPreferApn && preferredApn == null) { - Log.d(LOG_TAG, "PREFERRED APN is null"); - preferredApn = mActiveApn; - setPreferredApn(preferredApn.id); + if (canSetPreferApn && mPreferredApn == null) { + log("PREFERRED APN is null"); + mPreferredApn = mActiveApn; + setPreferredApn(mPreferredApn.id); } } else { SystemProperties.set("gsm.defaultpdpcontext.active", "false"); @@ -1143,13 +1040,14 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if(DBG) log("PDP setup failed " + cause); // Log this failure to the Event Logs. if (cause.isEventLoggable()) { - GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); + GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation()); EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL, cause.ordinal(), loc != null ? loc.getCid() : -1, TelephonyManager.getDefault().getNetworkType()); } - // No try for permanent failure + // Do not retry on permanent failure + // TODO: We should not fail permanently if more Apns to try! if (cause.isPermanentFail()) { notifyNoData(cause); notifyDataConnection(Phone.REASON_APN_FAILED); @@ -1157,8 +1055,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return; } - waitingApns.remove(0); - if (waitingApns.isEmpty()) { + mWaitingApns.remove(0); + if (mWaitingApns.isEmpty()) { // No more to try, start delayed retry startDelayedRetry(cause, reason); } else { @@ -1174,9 +1072,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { /** * Called when EVENT_DISCONNECT_DONE is received. */ - protected void onDisconnectDone(AsyncResult ar) { + @Override + protected void onDisconnectDone(int connId, AsyncResult ar) { + if(DBG) log("EVENT_DISCONNECT_DONE connId=" + connId); String reason = null; - if(DBG) log("EVENT_DISCONNECT_DONE"); if (ar.userObj instanceof String) { reason = (String) ar.userObj; } @@ -1202,22 +1101,24 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } protected void onPollPdp() { - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { // only poll when connected - phone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); + mPhone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS); } } + @Override protected void onVoiceCallStarted() { - if (state == State.CONNECTED && ! mGsmPhone.mSST.isConcurrentVoiceAndData()) { + if (mState == State.CONNECTED && ! mGsmPhone.mSST.isConcurrentVoiceAndData()) { stopNetStatPoll(); notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); } } + @Override protected void onVoiceCallEnded() { - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { if (!mGsmPhone.mSST.isConcurrentVoiceAndData()) { startNetStatPoll(); notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); @@ -1234,74 +1135,92 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } + @Override protected void onCleanUpConnection(boolean tearDown, String reason) { cleanUpConnection(tearDown, reason); } /** - * Based on the sim operator numeric, create a list for all possible pdps - * with all apns associated with that pdp - * - * + * Based on the sim operator numeric, create a list for all possible + * Data Connections and setup the preferredApn. */ private void createAllApnList() { - allApns = new ArrayList<ApnSetting>(); + mAllApns = new ArrayList<ApnSetting>(); String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric(); if (operator != null) { String selection = "numeric = '" + operator + "'"; - Cursor cursor = phone.getContext().getContentResolver().query( + Cursor cursor = mPhone.getContext().getContentResolver().query( Telephony.Carriers.CONTENT_URI, null, selection, null, null); if (cursor != null) { if (cursor.getCount() > 0) { - allApns = createApnList(cursor); - // TODO: Figure out where this fits in. This basically just - // writes the pap-secrets file. No longer tied to GsmDataConnection - // object. Not used on current platform (no ppp). - //GsmDataConnection pdp = pdpList.get(pdp_name); - //if (pdp != null && pdp.dataLink != null) { - // pdp.dataLink.setPasswordInfo(cursor); - //} + mAllApns = createApnList(cursor); } cursor.close(); } } - if (allApns.isEmpty()) { + if (mAllApns.isEmpty()) { if (DBG) log("No APN found for carrier: " + operator); - preferredApn = null; + mPreferredApn = null; notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN); } else { - preferredApn = getPreferredApn(); - Log.d(LOG_TAG, "Get PreferredAPN"); - if (preferredApn != null && !preferredApn.numeric.equals(operator)) { - preferredApn = null; + mPreferredApn = getPreferredApn(); + log("Get PreferredAPN"); + if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) { + mPreferredApn = null; setPreferredApn(-1); } } } - private void createAllPdpList() { - pdpList = new ArrayList<DataConnection>(); - DataConnection pdp; + /** Return the id for a new data connection */ + private int createDataConnection(String apnType) { + log("createDataConnection(" + apnType + ") E"); + RetryManager rm = new RetryManager(); + + if (apnType.equals(Phone.APN_TYPE_DEFAULT)) { + if (!rm.configure(SystemProperties.get("ro.gsm.data_retry_config"))) { + if (!rm.configure(DEFAULT_DATA_RETRY_CONFIG)) { + // Should never happen, log an error and default to a simple linear sequence. + log("Could not configure using DEFAULT_DATA_RETRY_CONFIG=" + + DEFAULT_DATA_RETRY_CONFIG); + rm.configure(20, 2000, 1000); + } + } + } else { + if (!rm.configure(SystemProperties.get("ro.gsm.2nd_data_retry_config"))) { + if (!rm.configure(SECONDARY_DATA_RETRY_CONFIG)) { + // Should never happen, log an error and default to a simple sequence. + log("Could note configure using SECONDARY_DATA_RETRY_CONFIG=" + + SECONDARY_DATA_RETRY_CONFIG); + rm.configure("max_retries=3, 333, 333, 333"); + } + } + } + + int id = mUniqueIdGenerator.getAndIncrement(); + DataConnection conn = GsmDataConnection.makeDataConnection(mGsmPhone, id, rm); + mDataConnections.put(id, conn); + mApnToDataConnectionId.put(apnType, id); - for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) { - pdp = GsmDataConnection.makeDataConnection(mGsmPhone); - pdpList.add(pdp); - } + log("createDataConnection(" + apnType + ") X id=" + id); + return id; } - private void destroyAllPdpList() { - if(pdpList != null) { - GsmDataConnection pdp; - pdpList.removeAll(pdpList); + private void destroyDataConnections() { + if(mDataConnections != null) { + log("destroyDataConnectionList clear mDataConnectionList"); + mDataConnections.clear(); + } else { + log("destroyDataConnectionList mDataConnecitonList is empty, ignore"); } } private ApnSetting fetchDunApn() { - Context c = phone.getContext(); + Context c = mPhone.getContext(); String apnData = Settings.Secure.getString(c.getContentResolver(), Settings.Secure.TETHER_DUN_APN); ApnSetting dunSetting = ApnSetting.fromString(apnData); @@ -1312,14 +1231,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } /** + * Build a list of APNs to be used to create PDP's. * + * @param requestedApnType * @return waitingApns list to be used to create PDP * error when waitingApns.isEmpty() */ - private ArrayList<ApnSetting> buildWaitingApns() { + private ArrayList<ApnSetting> buildWaitingApns(String requestedApnType) { ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>(); - if (mRequestedApnType.equals(Phone.APN_TYPE_DUN)) { + if (requestedApnType.equals(Phone.APN_TYPE_DUN)) { ApnSetting dun = fetchDunApn(); if (dun != null) apnList.add(dun); return apnList; @@ -1327,24 +1248,24 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric(); - if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { - if (canSetPreferApn && preferredApn != null) { - Log.i(LOG_TAG, "Preferred APN:" + operator + ":" - + preferredApn.numeric + ":" + preferredApn); - if (preferredApn.numeric.equals(operator)) { - Log.i(LOG_TAG, "Waiting APN set to preferred APN"); - apnList.add(preferredApn); + if (requestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { + if (canSetPreferApn && mPreferredApn != null) { + log("Preferred APN:" + operator + ":" + + mPreferredApn.numeric + ":" + mPreferredApn); + if (mPreferredApn.numeric.equals(operator)) { + log("Waiting APN set to preferred APN"); + apnList.add(mPreferredApn); return apnList; } else { setPreferredApn(-1); - preferredApn = null; + mPreferredApn = null; } } } - if (allApns != null) { - for (ApnSetting apn : allApns) { - if (apn.canHandleType(mRequestedApnType)) { + if (mAllApns != null) { + for (ApnSetting apn : mAllApns) { + if (apn.canHandleType(requestedApnType)) { apnList.add(apn); } } @@ -1357,7 +1278,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * @return the first apn found in waitingApns, null if none */ private ApnSetting getNextApn() { - ArrayList<ApnSetting> list = waitingApns; + ArrayList<ApnSetting> list = mWaitingApns; ApnSetting apn = null; if (list != null) { @@ -1388,7 +1309,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return; } - ContentResolver resolver = phone.getContext().getContentResolver(); + ContentResolver resolver = mPhone.getContext().getContentResolver(); resolver.delete(PREFERAPN_URI, null, null); if (pos >= 0) { @@ -1399,11 +1320,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } private ApnSetting getPreferredApn() { - if (allApns.isEmpty()) { + if (mAllApns.isEmpty()) { return null; } - Cursor cursor = phone.getContext().getContentResolver().query( + Cursor cursor = mPhone.getContext().getContentResolver().query( PREFERAPN_URI, new String[] { "_id", "name", "apn" }, null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); @@ -1417,7 +1338,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { int pos; cursor.moveToFirst(); pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)); - for(ApnSetting p:allApns) { + for(ApnSetting p:mAllApns) { if (p.id == pos && p.canHandleType(mRequestedApnType)) { cursor.close(); return p; @@ -1432,11 +1353,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return null; } + @Override public void handleMessage (Message msg) { - if (DBG) Log.d(LOG_TAG,"GSMDataConnTrack handleMessage "+msg); + if (DBG) log("GSMDataConnTrack handleMessage "+msg); if (!mGsmPhone.mIsTheCurrentActivePhone) { - Log.d(LOG_TAG, "Ignore GSM msgs since GSM phone is inactive"); + log("Ignore GSM msgs since GSM phone is inactive"); return; } @@ -1454,11 +1376,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { break; case EVENT_DATA_STATE_CHANGED: - onPdpStateChanged((AsyncResult) msg.obj, false); + onDataStateChanged((AsyncResult) msg.obj, false); break; case EVENT_GET_PDP_LIST_COMPLETE: - onPdpStateChanged((AsyncResult) msg.obj, true); + onDataStateChanged((AsyncResult) msg.obj, true); break; case EVENT_POLL_PDP: @@ -1486,7 +1408,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * PDP context and notify us with PDP_CONTEXT_CHANGED. * But we should stop the network polling and prevent reset PDP. */ - Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); + log("[DSAC DEB] " + "EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); stopNetStatPoll(); mIsPsRestricted = true; break; @@ -1496,12 +1418,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * When PS restrict is removed, we need setup PDP connection if * PDP connection is down. */ - Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); + log("[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); mIsPsRestricted = false; - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { startNetStatPoll(); } else { - if (state == State.FAILED) { + if (mState == State.FAILED) { cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED); mRetryMgr.resetRetryCount(); mReregisterOnReconnectFailure = false; @@ -1517,7 +1439,13 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } + @Override protected void log(String s) { Log.d(LOG_TAG, "[GsmDataConnectionTracker] " + s); } + + @Override + protected void loge(String s) { + Log.e(LOG_TAG, "[GsmDataConnectionTracker] " + s); + } } |