Merge "Add AccountKeys to FastPairAccountDevicesMetadataRequest." into tm-dev
diff --git a/nearby/halfsheet/res/drawable/fast_pair_ic_info.xml b/nearby/halfsheet/res/drawable/fast_pair_ic_info.xml
index cc514e5..7d61d1c 100644
--- a/nearby/halfsheet/res/drawable/fast_pair_ic_info.xml
+++ b/nearby/halfsheet/res/drawable/fast_pair_ic_info.xml
@@ -17,7 +17,8 @@
     android:width="24dp"
     android:height="24dp"
     android:viewportWidth="24.0"
-    android:viewportHeight="24.0">
+    android:viewportHeight="24.0"
+    android:tint="@color/fast_pair_half_sheet_subtitle_color">
     <path
         android:fillColor="@color/fast_pair_half_sheet_subtitle_color"
         android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
diff --git a/nearby/halfsheet/res/layout/fast_pair_device_pairing_fragment.xml b/nearby/halfsheet/res/layout/fast_pair_device_pairing_fragment.xml
index 24fcd83..7fbe229 100644
--- a/nearby/halfsheet/res/layout/fast_pair_device_pairing_fragment.xml
+++ b/nearby/halfsheet/res/layout/fast_pair_device_pairing_fragment.xml
@@ -73,50 +73,67 @@
     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:orientation="horizontal"
         app:layout_constraintTop_toBottomOf="@+id/connect_progressbar"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent">
+
       <ImageView
           android:id="@+id/info_icon"
+          android:layout_width="24dp"
+          android:layout_height="24dp"
+          app:srcCompat="@drawable/fast_pair_ic_info"
           android:layout_centerInParent="true"
           android:contentDescription="@null"
           android:layout_marginEnd="10dp"
           android:layout_toStartOf="@id/connect_btn"
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"/>
-      <Button
+          android:visibility="invisible" />
+
+      <com.google.android.material.button.MaterialButton
           android:id="@+id/connect_btn"
-          android:text="@string/common_connect"
-          android:layout_height="wrap_content"
           android:layout_width="@dimen/fast_pair_half_sheet_image_size"
+          android:layout_height="wrap_content"
+          android:text="@string/paring_action_connect"
           android:layout_centerInParent="true"
-          android:background="@color/fast_pair_half_sheet_button_color"
           style="@style/HalfSheetButton" />
+
     </RelativeLayout>
 
-    <Button
+    <com.google.android.material.button.MaterialButton
+        android:id="@+id/settings_btn"
+        android:text="@string/paring_action_settings"
+        android:layout_height="wrap_content"
+        android:layout_width="@dimen/fast_pair_half_sheet_image_size"
+        app:layout_constraintTop_toBottomOf="@+id/connect_progressbar"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        android:visibility="invisible"
+        style="@style/HalfSheetButton" />
+
+    <com.google.android.material.button.MaterialButton
         android:id="@+id/cancel_btn"
-        android:text="@string/common_done"
-        android:visibility="gone"
+        android:text="@string/paring_action_done"
+        android:visibility="invisible"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
         android:gravity="start|center_vertical"
         android:layout_marginTop="6dp"
-        android:layout_marginBottom="16dp"
         style="@style/HalfSheetButtonBorderless"/>
 
-    <Button
+    <com.google.android.material.button.MaterialButton
         android:id="@+id/setup_btn"
+        android:text="@string/paring_action_launch"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
         android:layout_marginTop="6dp"
         android:layout_marginBottom="16dp"
         android:background="@color/fast_pair_half_sheet_button_color"
-        android:visibility="gone"
+        android:visibility="invisible"
         android:layout_height="@dimen/fast_pair_half_sheet_bottom_button_height"
         android:layout_width="wrap_content"
         style="@style/HalfSheetButton" />
+
   </androidx.constraintlayout.widget.ConstraintLayout>
 
 </LinearLayout>
diff --git a/nearby/halfsheet/res/values/strings.xml b/nearby/halfsheet/res/values/strings.xml
index 12e3c23..01a82e4 100644
--- a/nearby/halfsheet/res/values/strings.xml
+++ b/nearby/halfsheet/res/values/strings.xml
@@ -16,9 +16,57 @@
 
 <resources>
 
-    <string name="common_done" description="After pairing process finish button text to dismiss halfsheet">Done</string>
-    <string name="common_save">Save</string>
-    <string name="common_connect" description="Button text to start connecting process">Connect</string>
-    <string name="fast_pair_app_launch_button" description="String on app launch half sheet button.">Set up</string>
+    <!--
+      ============================================================
+      PAIRING FRAGMENT
+      ============================================================
+    -->
 
+    <!--
+      A button shown to remind user setup is in progress. [CHAR LIMIT=30]
+    -->
+    <string name="fast_pair_setup_in_progress">Starting Setup&#x2026;</string>
+    <!--
+      Title text shown to remind user to setup a device through companion app. [CHAR LIMIT=40]
+    -->
+    <string name="fast_pair_title_setup">Set up device</string>
+    <!--
+      Title after we successfully pair with the audio device
+      [CHAR LIMIT=30]
+    -->
+    <string name="fast_pair_device_ready">Device connected</string>
+    <!-- Title text shown when peripheral device fail to connect to phone. [CHAR_LIMIT=30] -->
+    <string name="fast_pair_title_fail">Couldn\'t connect</string>
+
+    <!--
+      ============================================================
+      MISCELLANEOUS
+      ============================================================
+    -->
+
+    <!--
+      A button shown after paring process to dismiss the current activity.
+      [CHAR LIMIT=30]
+    -->
+    <string name="paring_action_done">Done</string>
+    <!--
+      A button shown for retroactive paring.
+      [CHAR LIMIT=30]
+     -->
+    <string name="paring_action_save">Save</string>
+    <!--
+      A button to start connecting process.
+      [CHAR LIMIT=30]
+     -->
+    <string name="paring_action_connect">Connect</string>
+    <!--
+      A button to launch a companion app.
+      [CHAR LIMIT=30]
+    -->
+    <string name="paring_action_launch">Set up</string>
+    <!--
+      A button to launch a bluetooth Settings page.
+      [CHAR LIMIT=20]
+    -->
+    <string name="paring_action_settings">Settings</string>
 </resources>
\ No newline at end of file
diff --git a/nearby/halfsheet/res/values/styles.xml b/nearby/halfsheet/res/values/styles.xml
index b48da70..917bb63 100644
--- a/nearby/halfsheet/res/values/styles.xml
+++ b/nearby/halfsheet/res/values/styles.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
-  <style name="HalfSheetStyle" parent="Theme.MaterialComponents.DayNight.NoActionBar">
+  <style name="HalfSheetStyle" parent="Theme.Material3.DayNight.NoActionBar">
     <item name="android:windowFrame">@null</item>
     <item name="android:windowBackground">@android:color/transparent</item>
     <item name="android:windowEnterAnimation">@anim/fast_pair_half_sheet_slide_in</item>
@@ -14,7 +14,7 @@
     <item name="android:windowTranslucentNavigation">true</item>
   </style>
 
-  <style name="HalfSheetButton" parent="@style/Widget.MaterialComponents.Button.TextButton">
+  <style name="HalfSheetButton" parent="@style/Widget.Material3.Button.TonalButton">
     <item name="android:textColor">@color/fast_pair_half_sheet_button_accent_text</item>
     <item name="android:backgroundTint">@color/fast_pair_half_sheet_button_color</item>
     <item name="android:textSize">@dimen/fast_pair_notification_text_size</item>
@@ -23,8 +23,7 @@
     <item name="android:textAllCaps">false</item>
   </style>
 
-  <style name="HalfSheetButtonBorderless"
-      parent="@style/Widget.MaterialComponents.Button.OutlinedButton">
+  <style name="HalfSheetButtonBorderless" parent="@style/Widget.Material3.Button.OutlinedButton">
     <item name="android:textColor">@color/fast_pair_half_sheet_button_text</item>
     <item name="android:strokeColor">@color/fast_pair_half_sheet_button_color</item>
     <item name="android:textAllCaps">false</item>
diff --git a/nearby/halfsheet/src/com/android/nearby/halfsheet/HalfSheetActivity.java b/nearby/halfsheet/src/com/android/nearby/halfsheet/HalfSheetActivity.java
index c495c35..9507b9b 100644
--- a/nearby/halfsheet/src/com/android/nearby/halfsheet/HalfSheetActivity.java
+++ b/nearby/halfsheet/src/com/android/nearby/halfsheet/HalfSheetActivity.java
@@ -19,22 +19,18 @@
 import static com.android.nearby.halfsheet.fragment.DevicePairingFragment.APP_LAUNCH_FRAGMENT_TYPE;
 import static com.android.server.nearby.common.bluetooth.fastpair.FastPairConstants.EXTRA_MODEL_ID;
 import static com.android.server.nearby.common.fastpair.service.UserActionHandlerBase.EXTRA_MAC_ADDRESS;
-import static com.android.server.nearby.fastpair.Constant.ACTION_FAST_PAIR_HALF_SHEET_BAN_STATE_RESET;
 import static com.android.server.nearby.fastpair.Constant.ACTION_FAST_PAIR_HALF_SHEET_CANCEL;
 import static com.android.server.nearby.fastpair.Constant.DEVICE_PAIRING_FRAGMENT_TYPE;
 import static com.android.server.nearby.fastpair.Constant.EXTRA_HALF_SHEET_INFO;
 import static com.android.server.nearby.fastpair.Constant.EXTRA_HALF_SHEET_TYPE;
 
-import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
-import android.util.DisplayMetrics;
 import android.util.Log;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
 import androidx.fragment.app.FragmentActivity;
 
 import com.android.nearby.halfsheet.fragment.DevicePairingFragment;
@@ -48,14 +44,12 @@
 import service.proto.Cache;
 
 /**
- * Half sheet activity to show pairing ux.
+ * A class show Fast Pair related information in Half sheet format.
  */
 public class HalfSheetActivity extends FragmentActivity {
 
-    public static final String EXTRA_HALF_SHEET_PENDING_INTENT_CALL_BACK =
-            "com.android.nearby.halfsheet.EXTRA_HALF_SHEET_PENDING_INTENT_CALL_BACK";
-    public static final String EXTRA_HALF_SHEET_PACKAGE_NAME =
-            "com.android.nearby.halfsheet.EXTRA_HALF_SHEET_PACKAGE_NAME";
+    public static final String TAG = "HalfSheetActivity";
+
     public static final String EXTRA_HALF_SHEET_CONTENT =
             "com.android.nearby.halfsheet.HALF_SHEET_CONTENT";
     public static final String EXTRA_TITLE =
@@ -72,38 +66,11 @@
             "com.android.nearby.halfsheet.EXTRA_HALF_SHEET_PAIRING_RESURFACE";
     public static final String ACTION_HALF_SHEET_FOREGROUND_STATE =
             "com.android.nearby.halfsheet.ACTION_HALF_SHEET_FOREGROUND_STATE";
-    public static final String ACTION_HALF_SHEET_BAN_ALL_ITEM =
-            "com.android.nearby.halfsheet.ACTION_HALF_SHEET_BAN_ALL_ITEM";
-    public static final String ACTION_HALF_SHEET_APP_LAUNCH_CLICKED =
-            "com.android.nearby.halfsheet.ACTION_HALF_SHEET_APP_LAUNCH_CLICKED";
-    public static final String ACTION_HALF_SHEET_WEAR_OS_CLICKED =
-            "com.android.nearby.halfsheet.ACTION_HALF_SHEET_WEAR_OS_CLICKED";
-    public static final String ACTION_HALF_SHEET_USER_COMPLETE_CONFIRMATION =
-            "com.android.nearby.halfsheet.ACTION_HALF_SHEET_USER_COMPLETE_CONFIRMATION";
-    public static final String ACTION_FAST_PAIR_HANDLE_CHIP_DEVICE =
-            "com.android.nearby.halfsheet.ACTION_FAST_PAIR_HANDLE_CHIP_DEVICE";
-    // Intent extra contains another intent that will trigger DiscoveryChimeraService to upload
-    // device
-    // information to the cloud.
-    public static final String EXTRA_HALF_SHEET_CLOUD_SYNC_INTENT =
-            "com.android.nearby.halfsheet.HALF_SHEET_CLOUD_SYNC_INTENT";
     // Intent extra contains the user gmail name eg. testaccount@gmail.com.
     public static final String EXTRA_HALF_SHEET_ACCOUNT_NAME =
             "com.android.nearby.halfsheet.HALF_SHEET_ACCOUNT_NAME";
     public static final String EXTRA_HALF_SHEET_FOREGROUND =
             "com.android.nearby.halfsheet.EXTRA_HALF_SHEET_FOREGROUND";
-    public static final String EXTRA_USER_CONSENT_SYNC_CONTACTS =
-            "com.android.nearby.halfsheet.EXTRA_USER_CONSENT_SYNC_CONTACTS";
-    public static final String EXTRA_USER_CONSENT_SYNC_SMS =
-            "com.android.nearby.halfsheet.EXTRA_USER_CONSENT_SYNC_SMS";
-    public static final String EXTRA_USER_CONFIRM_PASSKEY =
-            "com.android.nearby.halfsheet.EXTRA_USER_CONFIRM_PASSKEY";
-    public static final String CLASS_NAME =
-            "com.android.nearby.halfsheet.HalfSheetActivity";
-    public static final String ACTION_HALF_SHEET_STATUS_CHANGE =
-            "com.android.nearby.halfsheet.ACTION_HALF_SHEET_STATUS_CHANGE";
-    public static final String FINISHED_STATE = "FINISHED_STATE";
-    public static final String EXTRA_CLASSIC_MAC_ADDRESS = "EXTRA_CLASSIC_MAC_ADDRESS";
     public static final String ARG_FRAGMENT_STATE = "ARG_FRAGMENT_STATE";
     @Nullable
     private HalfSheetModuleFragment mHalfSheetModuleFragment;
@@ -128,7 +95,7 @@
                 mHalfSheetModuleFragment = DevicePairingFragment.newInstance(getIntent(),
                         savedInstanceState);
                 if (mHalfSheetModuleFragment == null) {
-                    Log.d("HalfSheetActivity", "device pairing fragment has error.");
+                    Log.d(TAG, "device pairing fragment has error.");
                     finish();
                     return;
                 }
@@ -136,13 +103,13 @@
             case APP_LAUNCH_FRAGMENT_TYPE:
                 // currentFragment = AppLaunchFragment.newInstance(getIntent());
                 if (mHalfSheetModuleFragment == null) {
-                    Log.v("HalfSheetActivity", "app launch fragment has error.");
+                    Log.v(TAG, "app launch fragment has error.");
                     finish();
                     return;
                 }
                 break;
             default:
-                Log.w("HalfSheetActivity", "there is no valid type for half sheet");
+                Log.w(TAG, "there is no valid type for half sheet");
                 finish();
                 return;
         }
@@ -159,23 +126,19 @@
         findViewById(R.id.background).setOnClickListener(v -> onCancelClicked());
         findViewById(R.id.card)
                 .setOnClickListener(
-                        v -> Log.v("HalfSheetActivity", "card view is clicked noop"));
+                        v -> Log.v(TAG, "card view is clicked noop"));
         try {
             mScanFastPairStoreItem =
                     Cache.ScanFastPairStoreItem.parseFrom(infoArray);
         } catch (InvalidProtocolBufferException e) {
             Log.w(
-                    "HalfSheetActivity", "error happens when pass info to half sheet");
+                    TAG, "error happens when pass info to half sheet");
         }
     }
 
     @Override
     protected void onStart() {
         super.onStart();
-        BroadcastUtils.sendBroadcast(
-                this,
-                new Intent(ACTION_HALF_SHEET_FOREGROUND_STATE)
-                        .putExtra(EXTRA_HALF_SHEET_FOREGROUND, true));
     }
 
     @Override
@@ -217,17 +180,18 @@
                         mScanFastPairStoreItem.getAddress())
                         && testScanFastPairStoreItem.getModelId().equals(
                         mScanFastPairStoreItem.getModelId())) {
-                    Log.d("HalfSheetActivity", "possible factory reset happens");
+                    Log.d(TAG, "possible factory reset happens");
                     halfSheetStateChange();
                 }
             } catch (InvalidProtocolBufferException | NullPointerException e) {
-                Log.w("HalfSheetActivity", "error happens when pass info to half sheet");
+                Log.w(TAG, "error happens when pass info to half sheet");
             }
         }
     }
 
     /** This function should be called when user click empty area and cancel button. */
     public void onCancelClicked() {
+        Log.d(TAG, "Cancels the half sheet and paring.");
         sendHalfSheetCancelBroadcast();
         finish();
     }
@@ -241,20 +205,6 @@
         finish();
     }
 
-    /**
-     * Change the half sheet ban state to active sometimes users leave half sheet to go to fast pair
-     * info page we do not want the behavior to be counted as dismiss.
-     */
-    public void sendBanStateResetBroadcast() {
-        if (mScanFastPairStoreItem != null) {
-            BroadcastUtils.sendBroadcast(
-                    this,
-                    new Intent(ACTION_FAST_PAIR_HALF_SHEET_BAN_STATE_RESET)
-                            .putExtra(EXTRA_MODEL_ID,
-                                    mScanFastPairStoreItem.getModelId().toLowerCase(Locale.ROOT)));
-        }
-    }
-
     private void sendHalfSheetCancelBroadcast() {
         BroadcastUtils.sendBroadcast(
                 this,
@@ -280,31 +230,10 @@
         }
     }
 
-    @Nullable
-    @VisibleForTesting
-    public HalfSheetModuleFragment getFragmentModel() {
-        return mHalfSheetModuleFragment;
-    }
-
     @Override
     public void setTitle(CharSequence title) {
         super.setTitle(title);
         TextView toolbarTitle = findViewById(R.id.toolbar_title);
         toolbarTitle.setText(title);
     }
-
-
-    /**
-     * This method converts dp unit to equivalent pixels, depending on device density.
-     *
-     * @param dp      A value in dp (density independent pixels) unit, which we need to convert into
-     *                pixels
-     * @param context Context to get resources and device specific display metrics
-     * @return A float value to represent px equivalent to dp depending on device density
-     */
-    private float convertDpToPixel(float dp, Context context) {
-        return dp
-                * ((float) context.getResources().getDisplayMetrics().densityDpi
-                / DisplayMetrics.DENSITY_DEFAULT);
-    }
 }
diff --git a/nearby/halfsheet/src/com/android/nearby/halfsheet/fragment/DevicePairingFragment.java b/nearby/halfsheet/src/com/android/nearby/halfsheet/fragment/DevicePairingFragment.java
index 74530de..a62c8cc 100644
--- a/nearby/halfsheet/src/com/android/nearby/halfsheet/fragment/DevicePairingFragment.java
+++ b/nearby/halfsheet/src/com/android/nearby/halfsheet/fragment/DevicePairingFragment.java
@@ -17,44 +17,35 @@
 
 import static android.text.TextUtils.isEmpty;
 
-import static com.android.nearby.halfsheet.HalfSheetActivity.ACTION_HALF_SHEET_STATUS_CHANGE;
 import static com.android.nearby.halfsheet.HalfSheetActivity.ARG_FRAGMENT_STATE;
-import static com.android.nearby.halfsheet.HalfSheetActivity.EXTRA_CLASSIC_MAC_ADDRESS;
 import static com.android.nearby.halfsheet.HalfSheetActivity.EXTRA_DESCRIPTION;
 import static com.android.nearby.halfsheet.HalfSheetActivity.EXTRA_HALF_SHEET_ACCOUNT_NAME;
 import static com.android.nearby.halfsheet.HalfSheetActivity.EXTRA_HALF_SHEET_CONTENT;
 import static com.android.nearby.halfsheet.HalfSheetActivity.EXTRA_HALF_SHEET_ID;
-import static com.android.nearby.halfsheet.HalfSheetActivity.EXTRA_HALF_SHEET_IS_RETROACTIVE;
-import static com.android.nearby.halfsheet.HalfSheetActivity.EXTRA_HALF_SHEET_IS_SUBSEQUENT_PAIR;
-import static com.android.nearby.halfsheet.HalfSheetActivity.EXTRA_HALF_SHEET_PAIRING_RESURFACE;
 import static com.android.nearby.halfsheet.HalfSheetActivity.EXTRA_TITLE;
-import static com.android.nearby.halfsheet.HalfSheetActivity.FINISHED_STATE;
+import static com.android.nearby.halfsheet.HalfSheetActivity.TAG;
+import static com.android.nearby.halfsheet.fragment.HalfSheetModuleFragment.HalfSheetFragmentState.FAILED;
+import static com.android.nearby.halfsheet.fragment.HalfSheetModuleFragment.HalfSheetFragmentState.FOUND_DEVICE;
 import static com.android.nearby.halfsheet.fragment.HalfSheetModuleFragment.HalfSheetFragmentState.NOT_STARTED;
-import static com.android.nearby.halfsheet.fragment.HalfSheetModuleFragment.HalfSheetFragmentState.RESULT_FAILURE;
-import static com.android.server.nearby.common.bluetooth.fastpair.FastPairConstants.EXTRA_MODEL_ID;
-import static com.android.server.nearby.fastpair.Constant.DISMISS;
+import static com.android.nearby.halfsheet.fragment.HalfSheetModuleFragment.HalfSheetFragmentState.PAIRED_LAUNCHABLE;
+import static com.android.nearby.halfsheet.fragment.HalfSheetModuleFragment.HalfSheetFragmentState.PAIRED_UNLAUNCHABLE;
+import static com.android.nearby.halfsheet.fragment.HalfSheetModuleFragment.HalfSheetFragmentState.PAIRING;
 import static com.android.server.nearby.fastpair.Constant.EXTRA_BINDER;
 import static com.android.server.nearby.fastpair.Constant.EXTRA_BUNDLE;
 import static com.android.server.nearby.fastpair.Constant.EXTRA_HALF_SHEET_INFO;
-import static com.android.server.nearby.fastpair.Constant.FAIL_STATE;
-import static com.android.server.nearby.fastpair.Constant.SUCCESS_STATE;
-import static com.android.server.nearby.fastpair.UserActionHandler.ACTION_FAST_PAIR;
-import static com.android.server.nearby.fastpair.UserActionHandler.EXTRA_PRIVATE_BLE_ADDRESS;
 
-import android.animation.AnimatorSet;
-import android.app.Activity;
-import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.res.Configuration;
-import android.nearby.IFastPairHalfSheetCallback;
+import android.graphics.Bitmap;
+import android.nearby.FastPairClient;
+import android.nearby.FastPairDevice;
+import android.nearby.FastPairStatusCallback;
+import android.nearby.NearbyDevice;
+import android.nearby.PairStatusMetadata;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -69,12 +60,13 @@
 
 import com.android.nearby.halfsheet.HalfSheetActivity;
 import com.android.nearby.halfsheet.R;
-import com.android.nearby.halfsheet.utils.BroadcastUtils;
 import com.android.nearby.halfsheet.utils.FastPairUtils;
-import com.android.server.nearby.fastpair.UserActionHandler;
+import com.android.nearby.halfsheet.utils.IconUtils;
 
 import com.google.protobuf.InvalidProtocolBufferException;
 
+import java.util.Objects;
+
 import service.proto.Cache.ScanFastPairStoreItem;
 
 /**
@@ -83,36 +75,38 @@
  * <p>This fragment will handle initial pairing subsequent pairing and retroactive pairing.
  */
 @SuppressWarnings("nullness")
-public class DevicePairingFragment extends HalfSheetModuleFragment {
+public class DevicePairingFragment extends HalfSheetModuleFragment implements
+        FastPairStatusCallback {
+    private TextView mTitleView;
+    private TextView mSubTitleView;
+    private ImageView mImage;
+
     private Button mConnectButton;
     private Button mSetupButton;
     private Button mCancelButton;
+    // Opens Bluetooth Settings.
+    private Button mSettingsButton;
     private ImageView mInfoIconButton;
     private ProgressBar mConnectProgressBar;
-    private View mRootView;
-    private TextView mSubTitle;
-    private TextView mTitle;
-    private ImageView mImage;
-    private ScanFastPairStoreItem mScanFastPairStoreItem;
-    // This open companion app intent will be triggered after user finish Fast Pair.
-    private Intent mOpenCompanionAppIntent;
-    // Indicates that the setup button is clicked before.
-    private boolean mSetupButtonClicked = false;
-    private boolean mIsSubsequentPair = false;
-    private boolean mIsPairingResurface = false;
-    private String mBluetoothMacAddress = "";
-    private HalfSheetFragmentState mFragmentState = NOT_STARTED;
-    private AnimatorSet mAnimatorSet = new AnimatorSet();
-    // True means pairing was successful and false means failed.
-    private Boolean mPairingResult = false;
+
     private Bundle mBundle;
 
-    public static final String APP_LAUNCH_FRAGMENT_TYPE = "APP_LAUNCH";
-    public static final String FAST_PAIR_CONSENT_FRAGMENT_TYPE = "FAST_PAIR_CONSENT";
-    private static final String ARG_SETUP_BUTTON_CLICKED = "SETUP_BUTTON_CLICKED";
-    public static final String RESULT_FAIL = "RESULT_FAIL";
-    private static final String ARG_PAIRING_RESULT = "PAIRING_RESULT";
+    private ScanFastPairStoreItem mScanFastPairStoreItem;
+    private FastPairClient mFastPairClient;
 
+    private @PairStatusMetadata.Status int mPairStatus = PairStatusMetadata.Status.UNKNOWN;
+    // True when there is a companion app to open.
+    private boolean mIsLaunchable;
+    private boolean mIsConnecting;
+    // Indicates that the setup button is clicked before.
+    private boolean mSetupButtonClicked = false;
+
+    // Holds the new text while we transition between the two.
+    private static final int TAG_PENDING_TEXT = R.id.toolbar_title;
+    public static final String APP_LAUNCH_FRAGMENT_TYPE = "APP_LAUNCH";
+
+    private static final String ARG_SETUP_BUTTON_CLICKED = "SETUP_BUTTON_CLICKED";
+    private static final String ARG_PAIRING_RESULT = "PAIRING_RESULT";
 
     /**
      * Create certain fragment according to the intent.
@@ -122,23 +116,15 @@
             Intent intent, @Nullable Bundle saveInstanceStates) {
         Bundle args = new Bundle();
         byte[] infoArray = intent.getByteArrayExtra(EXTRA_HALF_SHEET_INFO);
-        boolean isRetroactive = intent.getBooleanExtra(EXTRA_HALF_SHEET_IS_RETROACTIVE, false);
-        boolean isSubsequentPair = intent.getBooleanExtra(EXTRA_HALF_SHEET_IS_SUBSEQUENT_PAIR,
-                false);
-        boolean isPairingResurface = intent.getBooleanExtra(EXTRA_HALF_SHEET_PAIRING_RESURFACE,
-                false);
+
         Bundle bundle = intent.getBundleExtra(EXTRA_BUNDLE);
         String title = intent.getStringExtra(EXTRA_TITLE);
         String description = intent.getStringExtra(EXTRA_DESCRIPTION);
         String accountName = intent.getStringExtra(EXTRA_HALF_SHEET_ACCOUNT_NAME);
         String result = intent.getStringExtra(EXTRA_HALF_SHEET_CONTENT);
-        String publicAddress = intent.getStringExtra(EXTRA_CLASSIC_MAC_ADDRESS);
         int halfSheetId = intent.getIntExtra(EXTRA_HALF_SHEET_ID, 0);
 
         args.putByteArray(EXTRA_HALF_SHEET_INFO, infoArray);
-        args.putBoolean(EXTRA_HALF_SHEET_IS_RETROACTIVE, isRetroactive);
-        args.putBoolean(EXTRA_HALF_SHEET_IS_SUBSEQUENT_PAIR, isSubsequentPair);
-        args.putBoolean(EXTRA_HALF_SHEET_PAIRING_RESURFACE, isPairingResurface);
         args.putString(EXTRA_HALF_SHEET_ACCOUNT_NAME, accountName);
         args.putString(EXTRA_TITLE, title);
         args.putString(EXTRA_DESCRIPTION, description);
@@ -180,21 +166,22 @@
     public View onCreateView(
             LayoutInflater inflater, @Nullable ViewGroup container,
             @Nullable Bundle savedInstanceState) {
-        mRootView =
-                inflater.inflate(
-                        R.layout.fast_pair_device_pairing_fragment, container, /* attachToRoot= */
-                        false);
+        /* attachToRoot= */
+        View rootView = inflater.inflate(
+                R.layout.fast_pair_device_pairing_fragment, container, /* attachToRoot= */
+                false);
         if (getContext() == null) {
-            Log.d("DevicePairingFragment", "can't find the attached activity");
-            return mRootView;
+            Log.d(TAG, "can't find the attached activity");
+            return rootView;
         }
+
         Bundle args = getArguments();
         byte[] storeFastPairItemBytesArray = args.getByteArray(EXTRA_HALF_SHEET_INFO);
-        boolean isRetroactive = args.getBoolean(EXTRA_HALF_SHEET_IS_RETROACTIVE);
-        mIsSubsequentPair = args.getBoolean(EXTRA_HALF_SHEET_IS_SUBSEQUENT_PAIR);
-        mIsPairingResurface = args.getBoolean(EXTRA_HALF_SHEET_PAIRING_RESURFACE);
-        String accountName = args.getString(EXTRA_HALF_SHEET_ACCOUNT_NAME);
         mBundle = args.getBundle(EXTRA_BUNDLE);
+        if (mBundle != null) {
+            mFastPairClient = new FastPairClient(getContext(), mBundle.getBinder(EXTRA_BINDER));
+            mFastPairClient.registerHalfSheet(this);
+        }
         if (args.containsKey(ARG_FRAGMENT_STATE)) {
             mFragmentState = (HalfSheetFragmentState) args.getSerializable(ARG_FRAGMENT_STATE);
         }
@@ -202,86 +189,53 @@
             mSetupButtonClicked = args.getBoolean(ARG_SETUP_BUTTON_CLICKED);
         }
         if (args.containsKey(ARG_PAIRING_RESULT)) {
-            mPairingResult = args.getBoolean(ARG_PAIRING_RESULT);
-        } else {
-            mPairingResult = false;
+            mPairStatus = args.getInt(ARG_PAIRING_RESULT);
         }
 
-        // title = ((FragmentActivity) getContext()).findViewById(R.id.toolbar_title);
-        mConnectButton = mRootView.findViewById(R.id.connect_btn);
-        mImage = mRootView.findViewById(R.id.pairing_pic);
+        // Initiate views.
+        mTitleView = Objects.requireNonNull(getActivity()).findViewById(R.id.toolbar_title);
+        mSubTitleView = rootView.findViewById(R.id.header_subtitle);
+        mImage = rootView.findViewById(R.id.pairing_pic);
+        mConnectProgressBar = rootView.findViewById(R.id.connect_progressbar);
+        mConnectButton = rootView.findViewById(R.id.connect_btn);
+        mCancelButton = rootView.findViewById(R.id.cancel_btn);
+        mSettingsButton = rootView.findViewById(R.id.settings_btn);
+        mSetupButton = rootView.findViewById(R.id.setup_btn);
+        mInfoIconButton = rootView.findViewById(R.id.info_icon);
+        mInfoIconButton.setImageResource(R.drawable.fast_pair_ic_info);
 
-        mConnectProgressBar = mRootView.findViewById(R.id.connect_progressbar);
-        mConnectProgressBar.setVisibility(View.INVISIBLE);
+        try {
+            setScanFastPairStoreItem(ScanFastPairStoreItem.parseFrom(storeFastPairItemBytesArray));
+        } catch (InvalidProtocolBufferException e) {
+            Log.w(TAG,
+                    "DevicePairingFragment: error happens when pass info to half sheet");
+            return rootView;
+        }
 
+        // Config for landscape mode
         DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
         if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
-            mRootView.getLayoutParams().height = displayMetrics.heightPixels * 4 / 5;
-            mRootView.getLayoutParams().width = displayMetrics.heightPixels * 4 / 5;
+            rootView.getLayoutParams().height = displayMetrics.heightPixels * 4 / 5;
+            rootView.getLayoutParams().width = displayMetrics.heightPixels * 4 / 5;
             mImage.getLayoutParams().height = displayMetrics.heightPixels / 2;
             mImage.getLayoutParams().width = displayMetrics.heightPixels / 2;
             mConnectProgressBar.getLayoutParams().width = displayMetrics.heightPixels / 2;
             mConnectButton.getLayoutParams().width = displayMetrics.heightPixels / 2;
+            //TODO(b/213373051): Add cancel button
         }
 
-        mCancelButton = mRootView.findViewById(R.id.cancel_btn);
-        mSetupButton = mRootView.findViewById(R.id.setup_btn);
-        mInfoIconButton = mRootView.findViewById(R.id.info_icon);
-        mSubTitle = mRootView.findViewById(R.id.header_subtitle);
-        mSetupButton.setVisibility(View.GONE);
-        mInfoIconButton.setVisibility(View.GONE);
-
-        try {
-            if (storeFastPairItemBytesArray != null) {
-                mScanFastPairStoreItem =
-                        ScanFastPairStoreItem.parseFrom(storeFastPairItemBytesArray);
-            }
-
-            // If the fragmentState is not NOT_STARTED, it is because the fragment was just
-            // resumed from
-            // configuration change (e.g. rotating the screen or half-sheet resurface). Let's
-            // recover the
-            // UI directly.
-            if (mFragmentState != NOT_STARTED) {
-                switch (mFragmentState) {
-                    case PAIRING:
-                        Log.d("DevicePairingFragment", "redraw for PAIRING state.");
-                        return mRootView;
-                    case RESULT_SUCCESS:
-                        Log.d("DevicePairingFragment", "redraw for RESULT_SUCCESS state.");
-                        return mRootView;
-                    case RESULT_FAILURE:
-                        Log.d("DevicePairingFragment", "redraw for RESULT_FAILURE state.");
-                        return mRootView;
-                    default:
-                        // fall-out
-                        Log.d("DevicePairingFragment",
-                                "DevicePairingFragment: not supported state");
-                }
-            }
-            if (mIsPairingResurface) {
-                // Since the Settings contextual card has sent the pairing intent, we don't send the
-                // pairing intent here.
-                onConnectClick(/* sendPairingIntent= */ false);
-            } else {
-                mSubTitle.setText(this.getArguments().getString(EXTRA_DESCRIPTION));
-                mSubTitle.setText("");
-                mConnectButton.setOnClickListener(
-                        v -> onConnectClick(/* sendPairingIntent= */ true));
-                // Pairing fail half sheet resurface
-                if (this.getArguments().getString(EXTRA_HALF_SHEET_CONTENT).equals(RESULT_FAIL)) {
-                    mFragmentState = RESULT_FAILURE;
-                    showFailInfo();
-                } else {
-                    mConnectButton.setOnClickListener(
-                            v -> onConnectClick(/* sendPairingIntent= */ true));
-                }
-            }
-        } catch (InvalidProtocolBufferException e) {
-            Log.w("DevicePairingFragment",
-                    "DevicePairingFragment: error happens when pass info to half sheet");
+        Bitmap icon = IconUtils.getIcon(mScanFastPairStoreItem.getIconPng().toByteArray(),
+                mScanFastPairStoreItem.getIconPng().size());
+        if (icon != null) {
+            mImage.setImageBitmap(icon);
         }
-        return mRootView;
+        mConnectButton.setOnClickListener(v -> onConnectClick());
+        mCancelButton.setOnClickListener(v ->
+                ((HalfSheetActivity) getActivity()).onCancelClicked());
+        mSettingsButton.setOnClickListener(v -> onSettingsClicked());
+        mSetupButton.setOnClickListener(v -> onSetupClick());
+
+        return rootView;
     }
 
     @Override
@@ -294,19 +248,8 @@
     @Override
     public void onStart() {
         super.onStart();
-        if (getContext() != null) {
-            IntentFilter intentFilter = new IntentFilter();
-            intentFilter.addAction(ACTION_HALF_SHEET_STATUS_CHANGE);
-            BroadcastUtils.registerReceiver(getContext(), mHalfSheetChangeReceiver, intentFilter);
-        }
-    }
-
-    @Override
-    public void onStop() {
-        super.onStop();
-        if (getContext() != null) {
-            BroadcastUtils.unregisterReceiver(getContext(), mHalfSheetChangeReceiver);
-        }
+        Log.v(TAG, "onStart: invalidate states");
+        invalidateState();
     }
 
     @Override
@@ -315,118 +258,229 @@
 
         savedInstanceState.putSerializable(ARG_FRAGMENT_STATE, mFragmentState);
         savedInstanceState.putBoolean(ARG_SETUP_BUTTON_CLICKED, mSetupButtonClicked);
-        savedInstanceState.putBoolean(ARG_PAIRING_RESULT, mPairingResult);
-
-
+        savedInstanceState.putInt(ARG_PAIRING_RESULT, mPairStatus);
     }
 
-    @Nullable
-    private Intent createCompletionIntent(@Nullable String companionApp, @Nullable String address) {
-        if (isEmpty(companionApp)) {
-            return null;
-        } else if (FastPairUtils.isAppInstalled(getContext(), companionApp)
-                && isLaunchable(companionApp)) {
-            mOpenCompanionAppIntent = createCompanionAppIntent(companionApp, address);
-            return mOpenCompanionAppIntent;
-        } else {
-            return null;
-        }
-    }
-
-    @Nullable
-    private Intent createCompanionAppIntent(String packageName, @Nullable String address) {
-        return createCompanionAppIntent(getContext(), packageName, address);
-    }
-
-    @Nullable
-    private static Intent createCompanionAppIntent(
-            Context context, String packageName, @Nullable String address) {
-        Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName);
-        BluetoothManager manager = context.getSystemService(BluetoothManager.class);
-        if (address != null && manager != null) {
-            BluetoothAdapter adapter = manager.getAdapter();
-            if (intent != null && adapter != null) {
-                intent.putExtra(BluetoothDevice.EXTRA_DEVICE, adapter.getRemoteDevice(address));
-            }
-        }
-        return intent;
-    }
-
-    private void onConnectClick(boolean sendPairingIntent) {
-        if (mScanFastPairStoreItem == null) {
-            Log.w("DevicePairingFragment", "No pairing related information in half sheet");
-            return;
-        }
-
-        Log.d("FastPairHalfSheet", "on connect click");
-        // Allow user to setup device before connection setup.
-        // showPairingLastPhase();
-        ((Activity) getContext())
-                .findViewById(R.id.background)
-                .setOnClickListener(
-                        v ->
-                                Log.d("DevicePairingFragment",
-                                        "DevicePairingFragment: tap empty area do not dismiss "
-                                                + "half sheet when pairing."));
-        if (sendPairingIntent) {
-            try {
-                Log.d("FastPairHalfSheet", "on connect click");
-                Intent intent =
-                        new Intent(ACTION_FAST_PAIR)
-                                // Using the DiscoveryChimeraService notification id for
-                                // backwards compat
-                                .putExtra(
-                                        UserActionHandler.EXTRA_DISCOVERY_ITEM,
-                                        FastPairUtils.convertFrom(
-                                                mScanFastPairStoreItem).toByteArray())
-                                .putExtra(EXTRA_MODEL_ID, mScanFastPairStoreItem.getModelId())
-                                .putExtra(EXTRA_PRIVATE_BLE_ADDRESS,
-                                        mScanFastPairStoreItem.getAddress());
-                IFastPairHalfSheetCallback.Stub.asInterface(mBundle.getBinder(EXTRA_BINDER))
-                        .onHalfSheetConnectionConfirm(intent);
-            } catch (RemoteException e) {
-                Log.d("FastPairHalfSheet", "invoke callback fall");
-            }
-        }
-    }
-
-    private void onFailConnectClick() {
+    private void onSettingsClicked() {
         startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
     }
 
-    private final BroadcastReceiver mHalfSheetChangeReceiver =
-            new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    if (!ACTION_HALF_SHEET_STATUS_CHANGE.equals(intent.getAction())) {
-                        return;
-                    }
-                    if (SUCCESS_STATE.equals(intent.getStringExtra(FINISHED_STATE))) {
-                        mBluetoothMacAddress = intent.getStringExtra(EXTRA_CLASSIC_MAC_ADDRESS);
-                        showSuccessInfo();
-                        if (mOpenCompanionAppIntent != null) {
-                            //((HalfSheetActivity) getContext()).halfSheetStateChange();
-                            String companionApp =
-                                    FastPairUtils.getCompanionAppFromActionUrl(
-                                            mScanFastPairStoreItem.getActionUrl());
-                            // Redirect user to companion app if user choose to setup the app.
-                            // Recreate the intent
-                            // since the correct mac address just populated.
-                            startActivity(
-                                    createCompletionIntent(companionApp, mBluetoothMacAddress));
-                        }
-                    } else if (FAIL_STATE.equals(intent.getStringExtra(FINISHED_STATE))) {
-                        showFailInfo();
-                    } else if (DISMISS.equals(intent.getStringExtra(FINISHED_STATE))) {
-                        if (getContext() != null) {
-                            HalfSheetActivity activity = (HalfSheetActivity) getContext();
-                            activity.finish();
-                        }
-                    }
-                }
-            };
+    private void onSetupClick() {
+        String companionApp =
+                FastPairUtils.getCompanionAppFromActionUrl(mScanFastPairStoreItem.getActionUrl());
+        Intent intent =
+                FastPairUtils.createCompanionAppIntent(
+                        Objects.requireNonNull(getContext()),
+                        companionApp,
+                        mScanFastPairStoreItem.getAddress());
+        mSetupButtonClicked = true;
+        if (mFragmentState == PAIRED_LAUNCHABLE) {
+            if (intent != null) {
+                startActivity(intent);
+            }
+        } else {
+            Log.d(TAG, "onSetupClick: State is " + mFragmentState);
+        }
+    }
 
-    private boolean isLaunchable(String companionApp) {
-        return createCompanionAppIntent(companionApp, null) != null;
+    private void onConnectClick() {
+        if (mScanFastPairStoreItem == null) {
+            Log.w(TAG, "No pairing related information in half sheet");
+            return;
+        }
+        if (getFragmentState() == PAIRING) {
+            return;
+        }
+        mIsConnecting = true;
+        invalidateState();
+        mFastPairClient.connect(
+                new FastPairDevice.Builder()
+                        .addMedium(NearbyDevice.Medium.BLE)
+                        .setBluetoothAddress(mScanFastPairStoreItem.getAddress())
+                        .setData(FastPairUtils.convertFrom(mScanFastPairStoreItem)
+                                .toByteArray())
+                        .build());
+    }
+
+    // Receives callback from service.
+    @Override
+    public void onPairUpdate(FastPairDevice fastPairDevice, PairStatusMetadata pairStatusMetadata) {
+        @PairStatusMetadata.Status int status = pairStatusMetadata.getStatus();
+        if (status == PairStatusMetadata.Status.DISMISS && getActivity() != null) {
+            getActivity().finish();
+        }
+        mIsConnecting = false;
+        mPairStatus = status;
+        invalidateState();
+    }
+
+    @Override
+    public void invalidateState() {
+        HalfSheetFragmentState newState = NOT_STARTED;
+        if (mIsConnecting) {
+            newState = PAIRING;
+        } else {
+            switch (mPairStatus) {
+                case PairStatusMetadata.Status.SUCCESS:
+                    newState = mIsLaunchable ? PAIRED_LAUNCHABLE : PAIRED_UNLAUNCHABLE;
+                    break;
+                case PairStatusMetadata.Status.FAIL:
+                    newState = FAILED;
+                    break;
+                default:
+                    if (mScanFastPairStoreItem != null) {
+                        newState = FOUND_DEVICE;
+                    }
+            }
+        }
+        if (newState == mFragmentState) {
+            return;
+        }
+        setState(newState);
+    }
+
+    @Override
+    public void setState(HalfSheetFragmentState state) {
+        super.setState(state);
+        invalidateTitles();
+        invalidateButtons();
+    }
+
+    private void setScanFastPairStoreItem(ScanFastPairStoreItem item) {
+        mScanFastPairStoreItem = item;
+        invalidateLaunchable();
+    }
+
+    private void invalidateLaunchable() {
+        String companionApp =
+                FastPairUtils.getCompanionAppFromActionUrl(mScanFastPairStoreItem.getActionUrl());
+        if (isEmpty(companionApp)) {
+            mIsLaunchable = false;
+            return;
+        }
+        mIsLaunchable =
+                FastPairUtils.isLaunchable(Objects.requireNonNull(getContext()), companionApp);
+    }
+
+    private void invalidateButtons() {
+        mConnectProgressBar.setVisibility(View.INVISIBLE);
+        mConnectButton.setVisibility(View.INVISIBLE);
+        mCancelButton.setVisibility(View.INVISIBLE);
+        mSetupButton.setVisibility(View.INVISIBLE);
+        mSettingsButton.setVisibility(View.INVISIBLE);
+        mInfoIconButton.setVisibility(View.INVISIBLE);
+
+        switch (mFragmentState) {
+            case FOUND_DEVICE:
+                mInfoIconButton.setVisibility(View.VISIBLE);
+                mConnectButton.setVisibility(View.VISIBLE);
+                break;
+            case PAIRING:
+                mConnectProgressBar.setVisibility(View.VISIBLE);
+                mCancelButton.setVisibility(View.VISIBLE);
+                setBackgroundClickable(false);
+                break;
+            case PAIRED_LAUNCHABLE:
+                mCancelButton.setVisibility(View.VISIBLE);
+                mSetupButton.setVisibility(View.VISIBLE);
+                setBackgroundClickable(true);
+                break;
+            case FAILED:
+                mSettingsButton.setVisibility(View.VISIBLE);
+                setBackgroundClickable(true);
+                break;
+            case NOT_STARTED:
+            case PAIRED_UNLAUNCHABLE:
+            default:
+                mCancelButton.setVisibility(View.VISIBLE);
+                setBackgroundClickable(true);
+        }
+    }
+
+    private void setBackgroundClickable(boolean isClickable) {
+        HalfSheetActivity activity = (HalfSheetActivity) getActivity();
+        if (activity == null) {
+            Log.w(TAG, "setBackgroundClickable: failed to set clickable to " + isClickable
+                    + " because cannot get HalfSheetActivity.");
+            return;
+        }
+        View background = activity.findViewById(R.id.background);
+        if (background == null) {
+            Log.w(TAG, "setBackgroundClickable: failed to set clickable to " + isClickable
+                    + " cannot find background at HalfSheetActivity.");
+            return;
+        }
+        Log.d(TAG, "setBackgroundClickable to " + isClickable);
+        background.setClickable(isClickable);
+    }
+
+    private void invalidateTitles() {
+        String newTitle = getTitle();
+        invalidateTextView(mTitleView, newTitle);
+        String newSubTitle = getSubTitle();
+        invalidateTextView(mSubTitleView, newSubTitle);
+    }
+
+    private void invalidateTextView(TextView textView, String newText) {
+        CharSequence oldText =
+                textView.getTag(TAG_PENDING_TEXT) != null
+                        ? (CharSequence) textView.getTag(TAG_PENDING_TEXT)
+                        : textView.getText();
+        if (TextUtils.equals(oldText, newText)) {
+            return;
+        }
+        if (TextUtils.isEmpty(oldText)) {
+            // First time run. Don't animate since there's nothing to animate from.
+            textView.setText(newText);
+        } else {
+            textView.setTag(TAG_PENDING_TEXT, newText);
+            textView
+                    .animate()
+                    .alpha(0f)
+                    .setDuration(TEXT_ANIMATION_DURATION_MILLISECONDS)
+                    .withEndAction(
+                            () -> {
+                                textView.setText(newText);
+                                textView
+                                        .animate()
+                                        .alpha(1f)
+                                        .setDuration(TEXT_ANIMATION_DURATION_MILLISECONDS);
+                            });
+        }
+    }
+
+    private String getTitle() {
+        switch (mFragmentState) {
+            case PAIRED_LAUNCHABLE:
+                return getString(R.string.fast_pair_title_setup);
+            case FAILED:
+                return getString(R.string.fast_pair_title_fail);
+            case FOUND_DEVICE:
+            case NOT_STARTED:
+            case PAIRED_UNLAUNCHABLE:
+            default:
+                return mScanFastPairStoreItem.getDeviceName();
+        }
+    }
+
+    private String getSubTitle() {
+        switch (mFragmentState) {
+            case PAIRED_LAUNCHABLE:
+                return String.format(
+                        mScanFastPairStoreItem
+                                .getFastPairStrings()
+                                .getPairingFinishedCompanionAppInstalled(),
+                        mScanFastPairStoreItem.getDeviceName());
+            case FAILED:
+                return mScanFastPairStoreItem.getFastPairStrings().getPairingFailDescription();
+            case PAIRED_UNLAUNCHABLE:
+                getString(R.string.fast_pair_device_ready);
+            // fall through
+            case FOUND_DEVICE:
+            case NOT_STARTED:
+                return mScanFastPairStoreItem.getFastPairStrings().getInitialPairingDescription();
+            default:
+                return "";
+        }
     }
 }
diff --git a/nearby/halfsheet/src/com/android/nearby/halfsheet/fragment/HalfSheetModuleFragment.java b/nearby/halfsheet/src/com/android/nearby/halfsheet/fragment/HalfSheetModuleFragment.java
index 88caf95..f1db4d0 100644
--- a/nearby/halfsheet/src/com/android/nearby/halfsheet/fragment/HalfSheetModuleFragment.java
+++ b/nearby/halfsheet/src/com/android/nearby/halfsheet/fragment/HalfSheetModuleFragment.java
@@ -15,17 +15,23 @@
  */
 package com.android.nearby.halfsheet.fragment;
 
+import static com.android.nearby.halfsheet.HalfSheetActivity.TAG;
+import static com.android.nearby.halfsheet.fragment.HalfSheetModuleFragment.HalfSheetFragmentState.NOT_STARTED;
+
 import android.os.Bundle;
+import android.util.Log;
 
 import androidx.annotation.Nullable;
 import androidx.fragment.app.Fragment;
 
 
 /** Base class for all of the half sheet fragment. */
-// TODO(b/177675274): Resolve nullness suppression.
-@SuppressWarnings("nullness")
 public abstract class HalfSheetModuleFragment extends Fragment {
 
+    static final int TEXT_ANIMATION_DURATION_MILLISECONDS = 200;
+
+    HalfSheetFragmentState mFragmentState = NOT_STARTED;
+
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -38,26 +44,15 @@
 
     /** UI states of the half-sheet fragment. */
     public enum HalfSheetFragmentState {
-        NOT_STARTED,
-        SYNC_CONTACTS,
-        SYNC_SMS,
-        PROGRESSING,
-        CONFIRM_PASSKEY,
-        WRONG_PASSKEY,
-        PAIRING,
-        ADDITIONAL_SETUP_PROGRESS,
-        ADDITIONAL_SETUP_FINAL,
-        RESULT_SUCCESS,
-        RESULT_FAILURE,
-        FINISHED
-    }
-
-    /** Only used in {@link DevicePairingFragment} show pairing success info in half sheet. */
-    public void showSuccessInfo() {
-    }
-
-    /** Only used in {@link DevicePairingFragment} show pairing fail info in half sheet. */
-    public void showFailInfo() {
+        NOT_STARTED, // Initial status
+        FOUND_DEVICE, // When a device is found found from Nearby scan service
+        PAIRING, // When user taps 'Connect' and Fast Pair stars pairing process
+        PAIRED_LAUNCHABLE, // When pair successfully
+        // and we found a launchable companion app installed
+        PAIRED_UNLAUNCHABLE, // When pair successfully
+        // but we cannot find a companion app to launch it
+        FAILED, // When paring was failed
+        FINISHED // When the activity is about to end finished.
     }
 
     /**
@@ -67,6 +62,16 @@
      * activity.
      */
     public HalfSheetFragmentState getFragmentState() {
-        return HalfSheetFragmentState.NOT_STARTED;
+        return mFragmentState;
     }
+
+    void setState(HalfSheetFragmentState state) {
+        Log.v(TAG, "Settings state from " + mFragmentState + " to " + state);
+        mFragmentState = state;
+    }
+
+    /**
+     * Populate data to UI widgets according to the latest {@link HalfSheetFragmentState}.
+     */
+    abstract void invalidateState();
 }
diff --git a/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/BroadcastUtils.java b/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/BroadcastUtils.java
index cae2d8e..467997c 100644
--- a/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/BroadcastUtils.java
+++ b/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/BroadcastUtils.java
@@ -16,30 +16,13 @@
 
 package com.android.nearby.halfsheet.utils;
 
-
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 
 /**
  * Broadcast util class
  */
 public class BroadcastUtils {
-    /**
-     * Registers a list of broadcast receiver.
-     */
-    public static void registerReceiver(
-            Context context, BroadcastReceiver receiver, IntentFilter intentFilter) {
-        context.registerReceiver(receiver, intentFilter);
-    }
-
-    /**
-     * Unregisters the already registered receiver.
-     */
-    public static void unregisterReceiver(Context context, BroadcastReceiver receiver) {
-        context.unregisterReceiver(receiver);
-    }
 
     /**
      * Helps send broadcast.
diff --git a/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/FastPairUtils.java b/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/FastPairUtils.java
index fffb9e1..903ea90 100644
--- a/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/FastPairUtils.java
+++ b/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/FastPairUtils.java
@@ -38,8 +38,6 @@
  */
 public class FastPairUtils {
 
-    public static final String TAG = "HalfSheetActivity";
-
     /** FastPair util method check certain app is install on the device or not. */
     public static boolean isAppInstalled(Context context, String packageName) {
         try {
diff --git a/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/IconUtils.java b/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/IconUtils.java
index 0521b7b..218c756 100644
--- a/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/IconUtils.java
+++ b/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/IconUtils.java
@@ -16,7 +16,7 @@
 
 package com.android.nearby.halfsheet.utils;
 
-import static com.android.nearby.halfsheet.utils.FastPairUtils.TAG;
+import static com.android.nearby.halfsheet.HalfSheetActivity.TAG;
 
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/Constant.java b/nearby/service/java/com/android/server/nearby/fastpair/Constant.java
index 5958007..0695b5f 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/Constant.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/Constant.java
@@ -33,22 +33,11 @@
 
     public static final String EXTRA_BINDER = "com.android.server.nearby.fastpair.BINDER";
     public static final String EXTRA_BUNDLE = "com.android.server.nearby.fastpair.BUNDLE_EXTRA";
-    public static final String SUCCESS_STATE = "SUCCESS";
-    public static final String FAIL_STATE = "FAIL";
-    public static final String DISMISS = "DISMISS";
-    public static final String NEED_CONFIRM_PASSKEY = "NEED CONFIRM PASSKEY";
-    // device support assistant additional setup
-    public static final String NEED_ADDITIONAL_SETUP = "NEED ADDITIONAL SETUP";
-    public static final String SHOW_PAIRING_WITHOUT_INTERACTION =
-            "SHOW_PAIRING_WITHOUT_INTERACTION";
     public static final String ACTION_FAST_PAIR_HALF_SHEET_CANCEL =
             "com.android.nearby.ACTION_FAST_PAIR_HALF_SHEET_CANCEL";
-    public static final String ACTION_FAST_PAIR_HALF_SHEET_BAN_STATE_RESET =
-            "com.android.nearby.ACTION_FAST_PAIR_BAN_STATE_RESET";
     public static final String EXTRA_HALF_SHEET_INFO =
             "com.android.nearby.halfsheet.HALF_SHEET";
     public static final String EXTRA_HALF_SHEET_TYPE =
             "com.android.nearby.halfsheet.HALF_SHEET_TYPE";
     public static final String DEVICE_PAIRING_FRAGMENT_TYPE = "DEVICE_PAIRING";
-
 }
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java b/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java
index 793e126..1264ade 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java
@@ -16,21 +16,15 @@
 
 package com.android.server.nearby.fastpair;
 
-import static com.android.server.nearby.common.bluetooth.fastpair.BroadcastConstants.EXTRA_RETROACTIVE_PAIR;
-import static com.android.server.nearby.common.fastpair.service.UserActionHandlerBase.EXTRA_COMPANION_APP;
-import static com.android.server.nearby.fastpair.FastPairManager.EXTRA_NOTIFICATION_ID;
-
-import static com.google.common.io.BaseEncoding.base16;
 import static com.google.common.primitives.Bytes.concat;
 
 import android.accounts.Account;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.Intent;
+import android.nearby.FastPairDevice;
 import android.text.TextUtils;
 import android.util.Log;
 
-import androidx.annotation.UiThread;
 import androidx.annotation.WorkerThread;
 
 import com.android.server.nearby.common.bluetooth.fastpair.BluetoothAddress;
@@ -110,73 +104,60 @@
     /**
      * Pairing function.
      */
-    @UiThread
-    public void pair(Intent intent) {
-        String itemId = intent.getStringExtra(UserActionHandler.EXTRA_ITEM_ID);
-        int notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1);
-        byte[] discoveryItem = intent.getByteArrayExtra(UserActionHandler.EXTRA_DISCOVERY_ITEM);
-        String accountKeyString = intent.getStringExtra(UserActionHandler.EXTRA_FAST_PAIR_SECRET);
-        String companionApp = trimCompanionApp(intent.getStringExtra(EXTRA_COMPANION_APP));
-        byte[] accountKey = accountKeyString != null ? base16().decode(accountKeyString) : null;
-        boolean isRetroactivePair = intent.getBooleanExtra(EXTRA_RETROACTIVE_PAIR, false);
+    public void pair(FastPairDevice fastPairDevice) {
+        byte[] discoveryItem = fastPairDevice.getData();
+        String modelId = fastPairDevice.getModelId();
 
+        Log.v(TAG, "pair: fastPairDevice " + fastPairDevice);
         mEventLoop.postRunnable(
-                new NamedRunnable("fastPairWith=" + itemId) {
+                new NamedRunnable("fastPairWith=" + modelId) {
                     @Override
                     public void run() {
-                        DiscoveryItem item = null;
-                        if (discoveryItem != null) {
-                            try {
-                                item = new DiscoveryItem(mContext,
-                                        Cache.StoredDiscoveryItem.parseFrom(discoveryItem));
-                            } catch (InvalidProtocolBufferException e) {
-                                Log.w(TAG,
-                                        "Error parsing serialized discovery item with size "
-                                                + discoveryItem.length);
+                        try {
+                            DiscoveryItem item = new DiscoveryItem(mContext,
+                                    Cache.StoredDiscoveryItem.parseFrom(discoveryItem));
+                            if (TextUtils.isEmpty(item.getMacAddress())) {
+                                Log.w(TAG, "There is no mac address in the DiscoveryItem,"
+                                        + " ignore pairing");
                                 return;
                             }
+                            // Check enabled state to prevent multiple pair attempts if we get the
+                            // intent more than once (this can happen due to an Android platform
+                            // bug - b/31459521).
+                            if (item.getState()
+                                    != Cache.StoredDiscoveryItem.State.STATE_ENABLED) {
+                                Log.d(TAG, "Incorrect state, ignore pairing");
+                                return;
+                            }
+                            boolean useLargeNotifications =
+                                    item.getAuthenticationPublicKeySecp256R1() != null;
+                            FastPairNotificationManager fastPairNotificationManager =
+                                    new FastPairNotificationManager(mContext, item,
+                                            useLargeNotifications);
+                            FastPairHalfSheetManager fastPairHalfSheetManager =
+                                    Locator.get(mContext, FastPairHalfSheetManager.class);
+                            mFastPairCacheManager.saveDiscoveryItem(item);
+
+                            PairingProgressHandlerBase pairingProgressHandlerBase =
+                                    PairingProgressHandlerBase.create(
+                                            mContext,
+                                            item,
+                                            /* companionApp= */ null,
+                                            /* accountKey= */ null,
+                                            mFootprintsDeviceManager,
+                                            fastPairNotificationManager,
+                                            fastPairHalfSheetManager,
+                                            /* isRetroactivePair= */ false);
+
+                            pair(item,
+                                    /* accountKey= */ null,
+                                    /* companionApp= */ null,
+                                    pairingProgressHandlerBase);
+                        } catch (InvalidProtocolBufferException e) {
+                            Log.w(TAG,
+                                    "Error parsing serialized discovery item with size "
+                                            + discoveryItem.length);
                         }
-
-
-                        if (item == null || TextUtils.isEmpty(item.getMacAddress())) {
-                            Log.w(TAG, "Invalid DiscoveryItem, ignore pairing");
-                            return;
-                        }
-
-                        // Check enabled state to prevent multiple pair attempts if we get the
-                        // intent more than once (this can happen due to an Android platform
-                        // bug - b/31459521).
-                        if (item.getState() != Cache.StoredDiscoveryItem.State.STATE_ENABLED
-                                && !isRetroactivePair) {
-                            Log.d(TAG, "Incorrect state, ignore pairing");
-                            return;
-                        }
-
-                        boolean useLargeNotifications = accountKey != null
-                                || item.getAuthenticationPublicKeySecp256R1() != null;
-                        FastPairNotificationManager fastPairNotificationManager =
-                                notificationId == -1
-                                        ? new FastPairNotificationManager(mContext, item,
-                                        useLargeNotifications)
-                                        : new FastPairNotificationManager(mContext, item,
-                                                useLargeNotifications, notificationId);
-                        FastPairHalfSheetManager fastPairHalfSheetManager =
-                                Locator.get(mContext, FastPairHalfSheetManager.class);
-
-                        mFastPairCacheManager.saveDiscoveryItem(item);
-
-                        PairingProgressHandlerBase pairingProgressHandlerBase =
-                                PairingProgressHandlerBase.create(
-                                        mContext,
-                                        item,
-                                        companionApp,
-                                        accountKey,
-                                        mFootprintsDeviceManager,
-                                        fastPairNotificationManager,
-                                        fastPairHalfSheetManager,
-                                        isRetroactivePair);
-
-                        pair(item, accountKey, companionApp, pairingProgressHandlerBase);
                     }
                 });
     }
@@ -315,4 +296,4 @@
     interface Callback {
         void fastPairUpdateDeviceItemsEnabled(boolean enabled);
     }
-}
+}
\ No newline at end of file
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java b/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
index 9e1a718..3a3c962 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
@@ -56,6 +56,7 @@
 import com.android.server.nearby.fastpair.cache.DiscoveryItem;
 import com.android.server.nearby.fastpair.cache.FastPairCacheManager;
 import com.android.server.nearby.fastpair.footprint.FootprintsDeviceManager;
+import com.android.server.nearby.fastpair.halfsheet.FastPairHalfSheetManager;
 import com.android.server.nearby.fastpair.pairinghandler.PairingProgressHandlerBase;
 import com.android.server.nearby.util.FastPairDecoder;
 import com.android.server.nearby.util.ForegroundThread;
@@ -194,7 +195,7 @@
             @Nullable byte[] accountKey,
             FootprintsDeviceManager footprints,
             PairingProgressHandlerBase pairingProgressHandlerBase) {
-
+        FastPairHalfSheetManager manager = Locator.get(context, FastPairHalfSheetManager.class);
         try {
             pairingProgressHandlerBase.onPairingStarted();
             if (pairingProgressHandlerBase.skipWaitingScreenUnlock()) {
@@ -279,6 +280,10 @@
                 // Fast Pair one
                 connection.pair();
             }
+
+            // TODO(b/213373051): Merge logic with pairingProgressHandlerBase or delete the
+            // pairingProgressHandlerBase class.
+            manager.showPairingSuccessHalfSheet(connection.getPublicAddress());
             pairingProgressHandlerBase.onPairingSuccess(connection.getPublicAddress());
         } catch (BluetoothException
                 | InterruptedException
@@ -287,7 +292,11 @@
                 | ExecutionException
                 | PairingException
                 | GeneralSecurityException e) {
-            Log.e(TAG, "FastPair: Error");
+            Log.e(TAG, "Failed to pair.", e);
+
+            // TODO(b/213373051): Merge logic with pairingProgressHandlerBase or delete the
+            // pairingProgressHandlerBase class.
+            manager.showPairingFailed();
             pairingProgressHandlerBase.onPairingFailed(e);
         }
     }
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManager.java b/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManager.java
index 42839b2..6f79e6e 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManager.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManager.java
@@ -29,10 +29,14 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.nearby.FastPairDevice;
+import android.nearby.FastPairStatusCallback;
+import android.nearby.PairStatusMetadata;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.nearby.common.locator.LocatorContextWrapper;
 import com.android.server.nearby.fastpair.FastPairController;
 import com.android.server.nearby.fastpair.cache.DiscoveryItem;
@@ -47,27 +51,24 @@
  * Fast Pair ux manager for half sheet.
  */
 public class FastPairHalfSheetManager {
-    static final String ACTIVITY_INTENT_ACTION = "android.nearby.SHOW_HALFSHEET";
+    private static final String ACTIVITY_INTENT_ACTION = "android.nearby.SHOW_HALFSHEET";
     private static final String HALF_SHEET_CLASS_NAME =
             "com.android.nearby.halfsheet.HalfSheetActivity";
+    private static final String TAG = "FPHalfSheetManager";
 
     private String mHalfSheetApkPkgName;
-    private Context mContext;
-    private LocatorContextWrapper mLocatorContextWrapper;
+    private final LocatorContextWrapper mLocatorContextWrapper;
 
-    /**
-     * Construct function
-     */
+    FastPairService mFastPairService;
+
     public FastPairHalfSheetManager(Context context) {
-        mContext = context;
-        mLocatorContextWrapper = new LocatorContextWrapper(context);
+        this(new LocatorContextWrapper(context));
     }
 
-    /**
-     * Construct function for test
-     */
-    public FastPairHalfSheetManager(LocatorContextWrapper locatorContextWrapper) {
+    @VisibleForTesting
+    FastPairHalfSheetManager(LocatorContextWrapper locatorContextWrapper) {
         mLocatorContextWrapper = locatorContextWrapper;
+        mFastPairService = new FastPairService();
     }
 
     /**
@@ -79,14 +80,13 @@
             if (mLocatorContextWrapper != null) {
                 String packageName = getHalfSheetApkPkgName();
                 if (packageName == null) {
-                    Log.e("FastPairHalfSheetManager", "package name is null");
+                    Log.e(TAG, "package name is null");
                     return;
                 }
-                HalfSheetCallback callback = new HalfSheetCallback();
-                callback.setmFastPairController(
+                mFastPairService.setFastPairController(
                         mLocatorContextWrapper.getLocator().get(FastPairController.class));
                 Bundle bundle = new Bundle();
-                bundle.putBinder(EXTRA_BINDER, callback);
+                bundle.putBinder(EXTRA_BINDER, mFastPairService);
                 mLocatorContextWrapper
                         .startActivityAsUser(new Intent(ACTIVITY_INTENT_ACTION)
                                         .putExtra(EXTRA_HALF_SHEET_INFO,
@@ -97,11 +97,9 @@
                                         .setComponent(new ComponentName(packageName,
                                                 HALF_SHEET_CLASS_NAME)),
                                 UserHandle.CURRENT);
-
             }
         } catch (IllegalStateException e) {
-            Log.e("FastPairHalfSheetManager",
-                    "Can't resolve package that contains half sheet");
+            Log.e(TAG, "Can't resolve package that contains half sheet");
         }
     }
 
@@ -109,7 +107,15 @@
      * Shows pairing fail half sheet.
      */
     public void showPairingFailed() {
-        Log.d("FastPairHalfSheetManager", "show fail half sheet");
+        FastPairStatusCallback pairStatusCallback = mFastPairService.getPairStatusCallback();
+        if (pairStatusCallback != null) {
+            Log.v(TAG, "showPairingFailed: pairStatusCallback not NULL");
+            pairStatusCallback.onPairUpdate(new FastPairDevice.Builder().build(),
+                    new PairStatusMetadata(PairStatusMetadata.Status.FAIL));
+        } else {
+            Log.w(TAG, "FastPairHalfSheetManager failed to show success half sheet because "
+                    + "the pairStatusCallback is null");
+        }
     }
 
     /**
@@ -129,14 +135,22 @@
      * This function will handle pairing steps for half sheet.
      */
     public void showPairingHalfSheet(DiscoveryItem item) {
-        Log.d("FastPairHalfSheetManager", "show pairing half sheet");
+        Log.d(TAG, "show pairing half sheet");
     }
 
     /**
      * Shows pairing success info.
      */
     public void showPairingSuccessHalfSheet(String address) {
-        Log.d("FastPairHalfSheetManager", "show success half sheet");
+        FastPairStatusCallback pairStatusCallback = mFastPairService.getPairStatusCallback();
+        if (pairStatusCallback != null) {
+            pairStatusCallback.onPairUpdate(
+                    new FastPairDevice.Builder().setBluetoothAddress(address).build(),
+                    new PairStatusMetadata(PairStatusMetadata.Status.SUCCESS));
+        } else {
+            Log.w(TAG, "FastPairHalfSheetManager failed to show success half sheet because "
+                    + "the pairStatusCallback is null");
+        }
     }
 
     /**
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairService.java b/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairService.java
index 53c2c12..8c0d572 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairService.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairService.java
@@ -73,7 +73,13 @@
      * Asks the Fast Pair service to pair the device.
      */
     @Override
-    public void connect(FastPairDevice fastPairDevice) {}
+    public void connect(FastPairDevice fastPairDevice) {
+        if (mFastPairController != null) {
+            mFastPairController.pair(fastPairDevice);
+        } else {
+            Log.w(TAG, "Failed to connect because there is no FastPairController.");
+        }
+    }
 
     public FastPairStatusCallback getPairStatusCallback() {
         return mFastPairStatusCallback;
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/HalfSheetCallback.java b/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/HalfSheetCallback.java
deleted file mode 100644
index 2c792ed..0000000
--- a/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/HalfSheetCallback.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2021 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.server.nearby.fastpair.halfsheet;
-
-import android.content.Intent;
-import android.nearby.IFastPairHalfSheetCallback;
-import android.util.Log;
-
-import com.android.server.nearby.fastpair.FastPairController;
-
-
-/**
- * Callback to send ux action back to nearby service.
- */
-public class HalfSheetCallback extends IFastPairHalfSheetCallback.Stub {
-    private FastPairController mFastPairController;
-
-    public HalfSheetCallback() {
-    }
-
-    /**
-     * Set function for Fast Pair controller.
-     */
-    public void setmFastPairController(FastPairController fastPairController) {
-        mFastPairController = fastPairController;
-    }
-
-    /**
-     * Half Sheet connection button clicked.
-     */
-    @Override
-    public void onHalfSheetConnectionConfirm(Intent intent) {
-        Log.d("FastPairHalfSheet", "Call back receiver");
-        if (mFastPairController != null) {
-            mFastPairController.pair(intent);
-        }
-    }
-}
diff --git a/nearby/tests/multidevices/clients/proguard.flags b/nearby/tests/multidevices/clients/proguard.flags
index ec8f526..2e34dce 100644
--- a/nearby/tests/multidevices/clients/proguard.flags
+++ b/nearby/tests/multidevices/clients/proguard.flags
@@ -3,6 +3,11 @@
      *;
 }
 
+# Keep simulator reflection callback.
+-keep class com.android.server.nearby.common.bluetooth.fastpair.testing.** {
+     *;
+}
+
 # Do not touch Mobly.
 -keep class com.google.android.mobly.** {
   *;
diff --git a/nearby/tests/multidevices/host/Android.bp b/nearby/tests/multidevices/host/Android.bp
index 5aace96..b0adfba 100644
--- a/nearby/tests/multidevices/host/Android.bp
+++ b/nearby/tests/multidevices/host/Android.bp
@@ -16,7 +16,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-// Run the tests: atest -v CtsSeekerDiscoverProviderTest -- --replicate-parent-setup --multi-device-count 2
+// Run the tests: atest -v CtsSeekerDiscoverProviderTest
 python_test_host {
     name: "CtsSeekerDiscoverProviderTest",
     main: "seeker_discover_provider_test.py",
diff --git a/nearby/tests/unit/src/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManagerTest.java b/nearby/tests/unit/src/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManagerTest.java
index ab18f54..58e4c47 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManagerTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManagerTest.java
@@ -16,11 +16,6 @@
 
 package com.android.server.nearby.fastpair.halfsheet;
 
-
-import static com.android.server.nearby.fastpair.halfsheet.FastPairHalfSheetManager.ACTIVITY_INTENT_ACTION;
-
-import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -72,7 +67,6 @@
     public void setup() {
         MockitoAnnotations.initMocks(this);
 
-
         mScanFastPairStoreItem = Cache.ScanFastPairStoreItem.newBuilder()
                 .setAddress(BLEADDRESS)
                 .setDeviceName(NAME)
@@ -85,7 +79,6 @@
         ResolveInfo resolveInfo = new ResolveInfo();
         List<ResolveInfo> resolveInfoList = new ArrayList<>();
 
-
         mPackageManager = mock(PackageManager.class);
         when(mContextWrapper.getPackageManager()).thenReturn(mPackageManager);
         resolveInfo.activityInfo = new ActivityInfo();
@@ -108,8 +101,6 @@
 
         verify(mContextWrapper, atLeastOnce())
                 .startActivityAsUser(intentArgumentCaptor.capture(), eq(UserHandle.CURRENT));
-        Intent launchIntent = intentArgumentCaptor.getValue();
-        assertThat(launchIntent.getAction()).isEqualTo(ACTIVITY_INTENT_ACTION);
     }
 
     @Test
@@ -118,7 +109,6 @@
         ResolveInfo resolveInfo = new ResolveInfo();
         List<ResolveInfo> resolveInfoList = new ArrayList<>();
 
-
         mPackageManager = mock(PackageManager.class);
         when(mContextWrapper.getPackageManager()).thenReturn(mPackageManager);
         resolveInfo.activityInfo = new ActivityInfo();
@@ -142,6 +132,5 @@
 
         verify(mContextWrapper, never())
                 .startActivityAsUser(intentArgumentCaptor.capture(), eq(UserHandle.CURRENT));
-
     }
 }