diff options
-rw-r--r-- | core/java/android/animation/ObjectAnimator.java | 19 | ||||
-rwxr-xr-x | core/java/android/animation/ValueAnimator.java | 4 | ||||
-rw-r--r-- | core/java/android/preference/PreferenceActivity.java | 2 | ||||
-rw-r--r-- | core/res/res/layout/preference_list_content.xml | 1 | ||||
-rw-r--r-- | docs/html/guide/topics/security/security.jd | 76 | ||||
-rw-r--r-- | telephony/java/com/android/internal/telephony/CallManager.java | 190 |
6 files changed, 233 insertions, 59 deletions
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java index 6cb90bebb18c..31ddb0b51eb8 100644 --- a/core/java/android/animation/ObjectAnimator.java +++ b/core/java/android/animation/ObjectAnimator.java @@ -54,8 +54,9 @@ public final class ObjectAnimator<T> extends ValueAnimator<T> { * @param propertyName The name of the property being animated. */ public void setPropertyName(String propertyName) { + // mValues could be null if this is being constructed piecemeal. Just record the + // propertyName to be used later when setValues() is called if so. if (mValues != null) { - // mValues should always be non-null PropertyValuesHolder valuesHolder = mValues[0]; String oldName = valuesHolder.getPropertyName(); valuesHolder.setPropertyName(propertyName); @@ -63,6 +64,8 @@ public final class ObjectAnimator<T> extends ValueAnimator<T> { mValuesMap.put(propertyName, valuesHolder); } mPropertyName = propertyName; + // New property/values/target should cause re-initialization prior to starting + mInitialized = false; } /** @@ -154,6 +157,18 @@ public final class ObjectAnimator<T> extends ValueAnimator<T> { mTarget = target; } + @Override + public void setValues(T... values) { + if (mValues == null || mValues.length == 0) { + // No values yet - this animator is being constructed piecemeal. Init the values with + // whatever the current propertyName is + setValues(new PropertyValuesHolder[]{ + new PropertyValuesHolder(mPropertyName, (Object[])values)}); + } else { + super.setValues((T[]) values); + } + } + /** * This function is called immediately before processing the first animation * frame of an animation. If there is a nonzero <code>startDelay</code>, the @@ -197,6 +212,8 @@ public final class ObjectAnimator<T> extends ValueAnimator<T> { @Override public void setTarget(Object target) { mTarget = target; + // New property/values/target should cause re-initialization prior to starting + mInitialized = false; } @Override diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index 02b2dcece313..f81b1ea94b01 100755 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -258,6 +258,8 @@ public class ValueAnimator<T> extends Animator { PropertyValuesHolder valuesHolder = (PropertyValuesHolder) values[i]; mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder); } + // New property/values/target should cause re-initialization prior to starting + mInitialized = false; } /** @@ -292,6 +294,8 @@ public class ValueAnimator<T> extends Animator { PropertyValuesHolder valuesHolder = mValues[0]; valuesHolder.setValues(values); } + // New property/values/target should cause re-initialization prior to starting + mInitialized = false; } /** diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java index 076ba10ee30d..a6c7d9e23ef7 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -455,7 +455,7 @@ public abstract class PreferenceActivity extends ListActivity implements // visibility for other configurations. if (initialFragment != null && mSinglePane) { // Single pane, showing just a prefs fragment. - getListView().setVisibility(View.GONE); + findViewById(com.android.internal.R.id.headers).setVisibility(View.GONE); mPrefsContainer.setVisibility(View.VISIBLE); } else if (mHeaders.size() > 0) { mAdapter = new HeaderAdapter(this, mHeaders); diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml index 9661c643de8c..7c0b79140ae1 100644 --- a/core/res/res/layout/preference_list_content.xml +++ b/core/res/res/layout/preference_list_content.xml @@ -30,6 +30,7 @@ android:layout_weight="1"> <LinearLayout + android:id="@+id/headers" android:orientation="vertical" android:layout_width="0px" android:layout_height="match_parent" diff --git a/docs/html/guide/topics/security/security.jd b/docs/html/guide/topics/security/security.jd index dbc9866e859a..de0c6e57cc50 100644 --- a/docs/html/guide/topics/security/security.jd +++ b/docs/html/guide/topics/security/security.jd @@ -21,14 +21,15 @@ page.title=Security and Permissions </div> </div> -<p>Android is a multi-process system, in which each application (and parts of the -system) runs in its own process. Most security between applications and -the system is enforced at the process level through standard Linux facilities, -such as user and group IDs that are assigned to applications. -Additional finer-grained security features are provided -through a "permission" mechanism that enforces restrictions on the specific -operations that a particular process can perform, and per-URI permissions -for granting ad-hoc access to specific pieces of data.</p> +<p>Android is a privilege-separated operating system, in which each +application runs with a distinct system identity (Linux user ID and group +ID). Parts of the system are also separated into distinct identities. +Linux thereby isolates applications from each other and from the system.</p> + +<p>Additional finer-grained security features are provided through a +"permission" mechanism that enforces restrictions on the specific operations +that a particular process can perform, and per-URI permissions for granting +ad-hoc access to specific pieces of data.</p> <a name="arch"></a> <h2>Security Architecture</h2> @@ -38,39 +39,46 @@ application, by default, has permission to perform any operations that would adversely impact other applications, the operating system, or the user. This includes reading or writing the user's private data (such as contacts or e-mails), reading or writing another application's files, performing -network access, keeping the device awake, etc.<p> - -<p>An application's process runs in a security sandbox. The sandbox is designed -to prevent applications from disrupting each other, except by explicitly -declaring the <em>permissions</em> they need for additional capabilities not -provided by the basic sandbox. The system handles requests for permissions -in various ways, typically by automatically allowing or disallowing based on -certificates or by prompting the user. The permissions required by an -application are declared statically in that application, so they can be known -up-front at install time and will not change after that.</p> +network access, keeping the device awake, etc.</p> + +<p>Because the kernel sandboxes applications from each other, applications +must explicitly share resources and data. They do this by declaring the +<em>permissions</em> they need for additional capabilities not provided by +the basic sandbox. Applications statically declare the permissions they +require, and the Android system prompts the user for consent at the time the +application is installed. Android has no mechanism for granting permissions +dynamically (at run-time) because it complicates the user experience to the +detriment of security.</p> + +<p>The kernel is solely responsible for sandboxing applications from each +other. In particular the Dalvik VM is not a security boundary, and any app +can run native code (see <a href="/sdk/ndk/index.html">the Android NDK</a>). +All types of applications — Java, native, and hybrid — are +sandboxed in the same way and have the same degree of security from each +other.</p> <a name="signing"></a> <h2>Application Signing</h2> -<p>All Android applications (.apk files) must be signed with a certificate whose -private key is held by their developer. This certificate identifies the author -of the application. The certificate does <em>not</em> need to be signed by -a certificate authority: it is perfectly allowable, and typical, for Android -applications to use self-signed certificates. The certificate is used only -to establish trust relationships between applications, not for wholesale -control over whether an application can be installed. The most significant -ways that signatures impact security is by determining who can access -signature-based permissions and who can share user IDs.</p> - +<p>All Android applications (.apk files) must be signed with a certificate +whose private key is held by their developer. This certificate identifies +the author of the application. The certificate does <em>not</em> need to be +signed by a certificate authority: it is perfectly allowable, and typical, +for Android applications to use self-signed certificates. The purpose of +certificates in Android is to distinguish application authors. This allows +the system to grant or deny applications access to <a +href="/guide/topics/manifest/permission-element.html#plevel">signature-level +permissions</a> and to grant or deny an application's <a +href="/guide/topics/manifest/manifest-element.html#uid">request to be given +the same Linux identity</a> as another application.</p> <a name="userid"></a> <h2>User IDs and File Access</h2> -<p>Each Android package (.apk) file installed on the device is given its -own unique Linux user ID, creating a sandbox for it and preventing it from touching -other applications (or other applications from touching it). This user ID is -assigned to it when the application is installed on the device, and -remains constant for the duration of its life on that device.</p> +<p>At install time, Android gives each package a distinct Linux user ID. The +identity remains constant for the duration of the package's life on that +device. On a different device, the same package may have a different UID; +what matters is that each package has a distinct UID on a given device.</p> <p>Because security enforcement happens at the process level, the code of any two packages can not normally @@ -150,7 +158,7 @@ activities of other applications.</li> <li>Both sending and receiving broadcasts, to control who can receive your broadcast or who can send a broadcast to you.</li> <li>When accessing and operating on a content provider.</li> -<li>Binding or starting a service.</li> +<li>Binding to or starting a service.</li> </ul> diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java index 23cb42a3cc49..7c3508ff2189 100644 --- a/telephony/java/com/android/internal/telephony/CallManager.java +++ b/telephony/java/com/android/internal/telephony/CallManager.java @@ -54,9 +54,9 @@ import java.util.List; */ public final class CallManager { - private static final String LOG_TAG ="Phone"; + private static final String LOG_TAG ="CallManager"; private static final boolean DBG = true; - private static final boolean VDBG = false; + private static final boolean VDBG = true; private static final int EVENT_DISCONNECT = 100; private static final int EVENT_PRECISE_CALL_STATE_CHANGED = 101; @@ -291,6 +291,12 @@ public final class CallManager { Phone basePhone = getPhoneBase(phone); if (basePhone != null && !mPhones.contains(basePhone)) { + + if (VDBG) { + Log.d(LOG_TAG, "registerPhone(" + + phone.getPhoneName() + " " + phone + ")"); + } + if (mPhones.isEmpty()) { mDefaultPhone = basePhone; } @@ -312,6 +318,12 @@ public final class CallManager { Phone basePhone = getPhoneBase(phone); if (basePhone != null && mPhones.contains(basePhone)) { + + if (VDBG) { + Log.d(LOG_TAG, "unregisterPhone(" + + phone.getPhoneName() + " " + phone + ")"); + } + mPhones.remove(basePhone); mRingingCalls.remove(basePhone.getRingingCall()); mBackgroundCalls.remove(basePhone.getBackgroundCall()); @@ -466,7 +478,8 @@ public final class CallManager { Phone ringingPhone = ringingCall.getPhone(); if (VDBG) { - Log.d(LOG_TAG, "CallManager.acceptCall " + this); + Log.d(LOG_TAG, "acceptCall(" +ringingCall + " from " + ringingCall.getPhone() + ")"); + Log.d(LOG_TAG, this.toString()); } if ( hasActiveFgCall() ) { @@ -488,6 +501,11 @@ public final class CallManager { } ringingPhone.acceptCall(); + + if (VDBG) { + Log.d(LOG_TAG, "End acceptCall(" +ringingCall + ")"); + Log.d(LOG_TAG, this.toString()); + } } /** @@ -500,9 +518,19 @@ public final class CallManager { * @exception CallStateException when no call is ringing or waiting */ public void rejectCall(Call ringingCall) throws CallStateException { + if (VDBG) { + Log.d(LOG_TAG, "rejectCall(" +ringingCall + ")"); + Log.d(LOG_TAG, this.toString()); + } + Phone ringingPhone = ringingCall.getPhone(); ringingPhone.rejectCall(); + + if (VDBG) { + Log.d(LOG_TAG, "End rejectCall(" +ringingCall + ")"); + Log.d(LOG_TAG, this.toString()); + } } /** @@ -527,6 +555,11 @@ public final class CallManager { Phone activePhone = null; Phone heldPhone = null; + if (VDBG) { + Log.d(LOG_TAG, "switchHoldingAndActive(" +heldCall + ")"); + Log.d(LOG_TAG, this.toString()); + } + if (hasActiveFgCall()) { activePhone = getActiveFgCall().getPhone(); } @@ -542,6 +575,11 @@ public final class CallManager { if (heldPhone != null && heldPhone != activePhone) { heldPhone.switchHoldingAndActive(); } + + if (VDBG) { + Log.d(LOG_TAG, "End switchHoldingAndActive(" +heldCall + ")"); + Log.d(LOG_TAG, this.toString()); + } } /** @@ -556,6 +594,11 @@ public final class CallManager { Phone foregroundPhone = null; Phone backgroundPhone = null; + if (VDBG) { + Log.d(LOG_TAG, "hangupForegroundResumeBackground(" +heldCall + ")"); + Log.d(LOG_TAG, this.toString()); + } + if (hasActiveFgCall()) { foregroundPhone = getFgPhone(); if (heldCall != null) { @@ -569,6 +612,11 @@ public final class CallManager { } } } + + if (VDBG) { + Log.d(LOG_TAG, "End hangupForegroundResumeBackground(" +heldCall + ")"); + Log.d(LOG_TAG, this.toString()); + } } /** @@ -601,6 +649,13 @@ public final class CallManager { * In these cases, this operation may not be performed. */ public void conference(Call heldCall) throws CallStateException { + + if (VDBG) { + Log.d(LOG_TAG, "conference(" +heldCall + ")"); + Log.d(LOG_TAG, this.toString()); + } + + Phone fgPhone = getFgPhone(); if (fgPhone instanceof SipPhone) { ((SipPhone) fgPhone).conference(heldCall); @@ -609,6 +664,12 @@ public final class CallManager { } else { throw(new CallStateException("Can't conference foreground and selected background call")); } + + if (VDBG) { + Log.d(LOG_TAG, "End conference(" +heldCall + ")"); + Log.d(LOG_TAG, this.toString()); + } + } /** @@ -623,10 +684,13 @@ public final class CallManager { */ public Connection dial(Phone phone, String dialString) throws CallStateException { Phone basePhone = getPhoneBase(phone); + Connection result; + if (VDBG) { - Log.d(LOG_TAG, "CallManager.dial( phone=" + basePhone + ", dialString="+ dialString + ")"); + Log.d(LOG_TAG, " dial(" + basePhone + ", "+ dialString + ")"); Log.d(LOG_TAG, this.toString()); } + if ( hasActiveFgCall() ) { Phone activePhone = getActiveFgCall().getPhone(); boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle()); @@ -645,7 +709,15 @@ public final class CallManager { } } } - return basePhone.dial(dialString); + + result = basePhone.dial(dialString); + + if (VDBG) { + Log.d(LOG_TAG, "End dial(" + basePhone + ", "+ dialString + ")"); + Log.d(LOG_TAG, this.toString()); + } + + return result; } /** @@ -704,9 +776,20 @@ public final class CallManager { * In these cases, this operation may not be performed. */ public void explicitCallTransfer(Call heldCall) throws CallStateException { + if (VDBG) { + Log.d(LOG_TAG, " explicitCallTransfer(" + heldCall + ")"); + Log.d(LOG_TAG, this.toString()); + } + if (canTransfer(heldCall)) { heldCall.getPhone().explicitCallTransfer(); } + + if (VDBG) { + Log.d(LOG_TAG, "End explicitCallTransfer(" + heldCall + ")"); + Log.d(LOG_TAG, this.toString()); + } + } /** @@ -719,6 +802,7 @@ public final class CallManager { * @return null if phone doesn't have or support mmi code */ public List<? extends MmiCode> getPendingMmiCodes(Phone phone) { + Log.e(LOG_TAG, "getPendingMmiCodes not implemented"); return null; } @@ -731,6 +815,7 @@ public final class CallManager { * @return false if phone doesn't support ussd service */ public boolean sendUssdResponse(Phone phone, String ussdMessge) { + Log.e(LOG_TAG, "sendUssdResponse not implemented"); return false; } @@ -744,9 +829,19 @@ public final class CallManager { */ public void setMute(boolean muted) { + if (VDBG) { + Log.d(LOG_TAG, " setMute(" + muted + ")"); + Log.d(LOG_TAG, this.toString()); + } + if (hasActiveFgCall()) { getActiveFgCall().getPhone().setMute(muted); } + + if (VDBG) { + Log.d(LOG_TAG, "End setMute(" + muted + ")"); + Log.d(LOG_TAG, this.toString()); + } } /** @@ -774,11 +869,23 @@ public final class CallManager { * dtmf tone */ public boolean sendDtmf(char c) { + boolean result = false; + + if (VDBG) { + Log.d(LOG_TAG, " sendDtmf(" + c + ")"); + Log.d(LOG_TAG, this.toString()); + } + if (hasActiveFgCall()) { getActiveFgCall().getPhone().sendDtmf(c); - return true; + result = true; } - return false; + + if (VDBG) { + Log.d(LOG_TAG, "End sendDtmf(" + c + ")"); + Log.d(LOG_TAG, this.toString()); + } + return result; } /** @@ -791,11 +898,24 @@ public final class CallManager { * dtmf tone */ public boolean startDtmf(char c) { + boolean result = false; + + if (VDBG) { + Log.d(LOG_TAG, " startDtmf(" + c + ")"); + Log.d(LOG_TAG, this.toString()); + } + if (hasActiveFgCall()) { getActiveFgCall().getPhone().sendDtmf(c); - return true; + result = true; } - return false; + + if (VDBG) { + Log.d(LOG_TAG, "End startDtmf(" + c + ")"); + Log.d(LOG_TAG, this.toString()); + } + + return result; } /** @@ -803,7 +923,17 @@ public final class CallManager { * tone or no active call. */ public void stopDtmf() { + if (VDBG) { + Log.d(LOG_TAG, " stopDtmf()" ); + Log.d(LOG_TAG, this.toString()); + } + if (hasActiveFgCall()) getFgPhone().stopDtmf(); + + if (VDBG) { + Log.d(LOG_TAG, "End stopDtmf()"); + Log.d(LOG_TAG, this.toString()); + } } /** @@ -1469,70 +1599,91 @@ public final class CallManager { @Override public void handleMessage(Message msg) { + switch (msg.what) { case EVENT_DISCONNECT: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_DISCONNECT)"); mDisconnectRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_PRECISE_CALL_STATE_CHANGED: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_PRECISE_CALL_STATE_CHANGED)"); mPreciseCallStateRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_NEW_RINGING_CONNECTION: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_NEW_RINGING_CONNECTION)"); mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_UNKNOWN_CONNECTION: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_UNKNOWN_CONNECTION)"); mUnknownConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_INCOMING_RING: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_INCOMING_RING)"); // The event may come from RIL who's not aware of an ongoing fg call if (!hasActiveFgCall()) { mIncomingRingRegistrants.notifyRegistrants((AsyncResult) msg.obj); } break; case EVENT_RINGBACK_TONE: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_RINGBACK_TONE)"); mRingbackToneRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_IN_CALL_VOICE_PRIVACY_ON: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_IN_CALL_VOICE_PRIVACY_ON)"); mInCallVoicePrivacyOnRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_IN_CALL_VOICE_PRIVACY_OFF: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_IN_CALL_VOICE_PRIVACY_OFF)"); mInCallVoicePrivacyOffRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_CALL_WAITING: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_CALL_WAITING)"); mCallWaitingRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_DISPLAY_INFO: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_DISPLAY_INFO)"); mDisplayInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_SIGNAL_INFO: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SIGNAL_INFO)"); mSignalInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_CDMA_OTA_STATUS_CHANGE: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_CDMA_OTA_STATUS_CHANGE)"); mCdmaOtaStatusChangeRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_RESEND_INCALL_MUTE: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_RESEND_INCALL_MUTE)"); mResendIncallMuteRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_MMI_INITIATE: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_MMI_INITIATE)"); mMmiInitiateRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_MMI_COMPLETE: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_MMI_COMPLETE)"); mMmiCompleteRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_ECM_TIMER_RESET: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_ECM_TIMER_RESET)"); mEcmTimerResetRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_SUBSCRIPTION_INFO_READY: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SUBSCRIPTION_INFO_READY)"); mSubscriptionInfoReadyRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_SUPP_SERVICE_FAILED: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SUPP_SERVICE_FAILED)"); mSuppServiceFailedRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_SERVICE_STATE_CHANGED: + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SERVICE_STATE_CHANGED)"); mServiceStateChangedRegistrants.notifyRegistrants((AsyncResult) msg.obj); break; case EVENT_POST_DIAL_CHARACTER: // we need send the character that is being processed in msg.arg1 // so can't use notifyRegistrants() + if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_POST_DIAL_CHARACTER)"); for(int i=0; i < mPostDialCharacterRegistrants.size(); i++) { Message notifyMsg; notifyMsg = ((Registrant)mPostDialCharacterRegistrants.get(i)).messageForRegistrant(); @@ -1551,36 +1702,29 @@ public final class CallManager { StringBuilder b = new StringBuilder(); b.append("########### Dump CallManager ############"); - b.append("\nCM state = " + getState()); + b.append("\nCallManager state = " + getState()); call = getActiveFgCall(); - b.append("\n - FG call: " + getActiveFgCallState()); + b.append("\n - Foreground: " + getActiveFgCallState()); b.append(" from " + call.getPhone()); b.append("\n Conn: ").append(getFgCallConnections()); call = getFirstActiveBgCall(); - b.append("\n - BG call: " + call.getState()); + b.append("\n - Background: " + call.getState()); b.append(" from " + call.getPhone()); b.append("\n Conn: ").append(getBgCallConnections()); call = getFirstActiveRingingCall(); - b.append("\n - RINGING call: " +call.getState()); + b.append("\n - Ringing: " +call.getState()); b.append(" from " + call.getPhone()); - b.append("\n"); for (Phone phone : getAllPhones()) { if (phone != null) { b.append("\n Phone: " + phone + ", name = " + phone.getPhoneName() + ", state = " + phone.getState()); call = phone.getForegroundCall(); - b.append("\n - FG call: ").append(call); - b.append(" State: ").append(call.getState()); - b.append("\n Conn: ").append(call.getConnections()); + b.append("\n - Foreground: ").append(call); call = phone.getBackgroundCall(); - b.append("\n - BG call: ").append(call); - b.append(" State: ").append(call.getState()); - b.append("\n Conn: ").append(call.getConnections()); + b.append(" Background: ").append(call); call = phone.getRingingCall(); - b.append("\n - RINGING call: ").append(call); - b.append( " State: ").append(call.getState()); - b.append("\n Conn: ").append(call.getConnections()); + b.append(" Ringing: ").append(call); } } b.append("\n########## End Dump CallManager ##########"); |