Merge "Telecomm: Use Uri for handle" into master-nova
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index 08a50ab..849c876 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -272,6 +272,28 @@
     }
 
     /**
+     * Puts the call on hold if it is currently active.
+     */
+    void hold() {
+        Preconditions.checkNotNull(mCallService);
+
+        if (mState == CallState.ACTIVE) {
+            mCallService.hold(mId);
+        }
+    }
+
+    /**
+     * Releases the call from hold if it is currently active.
+     */
+    void unhold() {
+        Preconditions.checkNotNull(mCallService);
+
+        if (mState == CallState.ON_HOLD) {
+            mCallService.unhold(mId);
+        }
+    }
+
+    /**
      * @return An object containing read-only information about this call.
      */
     CallInfo toCallInfo() {
diff --git a/src/com/android/telecomm/CallServiceAdapter.java b/src/com/android/telecomm/CallServiceAdapter.java
index 1e830d5..e30d338 100644
--- a/src/com/android/telecomm/CallServiceAdapter.java
+++ b/src/com/android/telecomm/CallServiceAdapter.java
@@ -172,6 +172,16 @@
         });
     }
 
+    /** {@inheritDoc} */
+    @Override public void setOnHold(final String callId) {
+        checkValidCallId(callId);
+        mHandler.post(new Runnable() {
+            @Override public void run() {
+                mCallsManager.markCallAsOnHold(callId);
+            }
+        });
+    }
+
     /**
      * Adds the specified call ID to the list of pending outgoing call IDs.
      * TODO(gilad): Consider passing the call processor (instead of the ID) both here and in the
diff --git a/src/com/android/telecomm/CallServiceWrapper.java b/src/com/android/telecomm/CallServiceWrapper.java
index 807f427..5585fc7 100644
--- a/src/com/android/telecomm/CallServiceWrapper.java
+++ b/src/com/android/telecomm/CallServiceWrapper.java
@@ -146,6 +146,28 @@
         }
     }
 
+    /** See {@link ICallService#hold}. */
+    public void hold(String callId) {
+        if (isServiceValid("hold")) {
+            try {
+                mServiceInterface.hold(callId);
+            } catch (RemoteException e) {
+                Log.e(this, e, "Failed to put on hold for call %s", callId);
+            }
+        }
+    }
+
+    /** See {@link ICallService#unhold}. */
+    public void unhold(String callId) {
+        if (isServiceValid("unhold")) {
+            try {
+                mServiceInterface.unhold(callId);
+            } catch (RemoteException e) {
+                Log.e(this, e, "Failed to remove from hold for call %s", callId);
+            }
+        }
+    }
+
     /**
      * Starts retrieval of details for an incoming call. Details are returned through the
      * call-service adapter using the specified call ID. Upon failure, the specified error callback
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index 556c770..26f7ac1 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -259,6 +259,40 @@
         audioManager.abandonAudioFocusForCall();
     }
 
+    /**
+     * Instructs Telecomm to put the specified call on hold. Intended to be invoked by the
+     * in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered by
+     * the user hitting the hold button during an active call.
+     *
+     * @param callId The ID of the call.
+     */
+    void holdCall(String callId) {
+        Call call = mCalls.get(callId);
+        if (call == null) {
+            Log.w(this, "Unknown call (%s) asked to be put on hold", callId);
+        } else {
+            Log.d(this, "Putting call on hold: (%s)", callId);
+            call.hold();
+        }
+    }
+
+    /**
+     * Instructs Telecomm to release the specified call from hold. Intended to be invoked by
+     * the in-call app through {@link InCallAdapter} for an ongoing call. This is usually triggered
+     * by the user hitting the hold button during a held call.
+     *
+     * @param callId The ID of the call
+     */
+    void unholdCall(String callId) {
+        Call call = mCalls.get(callId);
+        if (call == null) {
+            Log.w(this, "Unknown call (%s) asked to be removed from hold", callId);
+        } else {
+            Log.d(this, "Removing call from hold: (%s)", callId);
+            call.unhold();
+        }
+    }
+
     void markCallAsRinging(String callId) {
         setCallState(callId, CallState.RINGING);
     }
@@ -283,6 +317,13 @@
         audioManager.setSpeakerphoneOn(false);
     }
 
+    void markCallAsOnHold(String callId) {
+        setCallState(callId, CallState.ON_HOLD);
+
+        // Notify the in-call UI
+        mInCallController.markCallAsOnHold(callId);
+    }
+
     /**
      * Marks the specified call as DISCONNECTED and notifies the in-call app. If this was the last
      * live call, then also disconnect from the in-call controller.
@@ -383,6 +424,7 @@
         switch (call.getState()) {
             case DIALING:
             case ACTIVE:
+            case ON_HOLD:
                 callState = TelephonyManager.EXTRA_STATE_OFFHOOK;
                 break;
 
diff --git a/src/com/android/telecomm/InCallAdapter.java b/src/com/android/telecomm/InCallAdapter.java
index 7232abf..37dc3b9 100644
--- a/src/com/android/telecomm/InCallAdapter.java
+++ b/src/com/android/telecomm/InCallAdapter.java
@@ -68,4 +68,24 @@
             }
         });
     }
+
+    /** {@inheritDoc} */
+    @Override
+    public void holdCall(final String callId) {
+        mHandler.post(new Runnable() {
+            @Override public void run() {
+                mCallsManager.holdCall(callId);
+            }
+        });
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void unholdCall(final String callId) {
+        mHandler.post(new Runnable() {
+            @Override public void run() {
+                mCallsManager.unholdCall(callId);
+            }
+        });
+    }
 }
diff --git a/src/com/android/telecomm/InCallController.java b/src/com/android/telecomm/InCallController.java
index 4da9190..4f863c5 100644
--- a/src/com/android/telecomm/InCallController.java
+++ b/src/com/android/telecomm/InCallController.java
@@ -141,6 +141,17 @@
         }
     }
 
+    void markCallAsOnHold(String callId) {
+        try {
+            if (mInCallService != null) {
+                Log.i(this, "Mark call as HOLD: %s", callId);
+                mInCallService.setOnHold(callId);
+            }
+        } catch (RemoteException e) {
+            Log.e(this, e, "Exception attempting to markCallAsHeld.");
+        }
+    }
+
     /**
      * Unbinds an existing bound connection to the in-call app.
      */
diff --git a/src/com/android/telecomm/Timeouts.java b/src/com/android/telecomm/Timeouts.java
index 05c26db..0fab3c4 100644
--- a/src/com/android/telecomm/Timeouts.java
+++ b/src/com/android/telecomm/Timeouts.java
@@ -1,4 +1,18 @@
-// Copyright 2014 Google Inc. All Rights Reserved.
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 package com.android.telecomm;
 
diff --git a/tests/src/com/android/telecomm/testcallservice/TestCallService.java b/tests/src/com/android/telecomm/testcallservice/TestCallService.java
index f9e05d3..d3c44a8 100644
--- a/tests/src/com/android/telecomm/testcallservice/TestCallService.java
+++ b/tests/src/com/android/telecomm/testcallservice/TestCallService.java
@@ -149,6 +149,20 @@
 
     /** {@inheritDoc} */
     @Override
+    public void hold(String callId) {
+        Log.i(TAG, "hold(" + callId + ")");
+        mTelecommAdapter.setOnHold(callId);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void unhold(String callId) {
+        Log.i(TAG, "unhold(" + callId + ")");
+        mTelecommAdapter.setActive(callId);
+    }
+
+    /** {@inheritDoc} */
+    @Override
     public boolean onUnbind(Intent intent) {
         mMediaPlayer = null;