blob: 65d670584971aa93a59ab9bc5277791e6ab24635 [file] [log] [blame]
/*
* Copyright (c) 2023 Project CHIP Authors
* All rights reserved.
*
* 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.matter.casting;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.R;
import com.matter.casting.core.CastingPlayer;
import com.matter.casting.core.CastingPlayerDiscovery;
import com.matter.casting.core.MatterCastingPlayerDiscovery;
import com.matter.casting.support.MatterError;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class DiscoveryExampleFragment extends Fragment {
private static final String TAG = DiscoveryExampleFragment.class.getSimpleName();
// 35 represents device type of Matter Casting Player
private static final Long DISCOVERY_TARGET_DEVICE_TYPE = 35L;
private static final int DISCOVERY_RUNTIME_SEC = 15;
private TextView matterDiscoveryMessageTextView;
private TextView matterDiscoveryErrorMessageTextView;
private static final List<CastingPlayer> castingPlayerList = new ArrayList<>();
private static ArrayAdapter<CastingPlayer> arrayAdapter;
// Get a singleton instance of the MatterCastingPlayerDiscovery
private static final CastingPlayerDiscovery matterCastingPlayerDiscovery =
MatterCastingPlayerDiscovery.getInstance();
/**
* Implementation of a CastingPlayerChangeListener used to listen to changes in the discovered
* CastingPlayers
*/
private static final CastingPlayerDiscovery.CastingPlayerChangeListener
castingPlayerChangeListener =
new CastingPlayerDiscovery.CastingPlayerChangeListener() {
private final String TAG =
CastingPlayerDiscovery.CastingPlayerChangeListener.class.getSimpleName();
@Override
public void onAdded(CastingPlayer castingPlayer) {
Log.i(
TAG,
"onAdded() Discovered CastingPlayer deviceId: " + castingPlayer.getDeviceId());
// Display CastingPlayer info on the screen
new Handler(Looper.getMainLooper())
.post(
() -> {
arrayAdapter.add(castingPlayer);
});
}
@Override
public void onChanged(CastingPlayer castingPlayer) {
Log.i(
TAG,
"onChanged() Discovered changes to CastingPlayer with deviceId: "
+ castingPlayer.getDeviceId());
// Update the CastingPlayer on the screen
new Handler(Looper.getMainLooper())
.post(
() -> {
final Optional<CastingPlayer> playerInList =
castingPlayerList
.stream()
.filter(node -> castingPlayer.equals(node))
.findFirst();
if (playerInList.isPresent()) {
Log.d(
TAG,
"onChanged() Updating existing CastingPlayer entry "
+ playerInList.get().getDeviceId()
+ " in castingPlayerList list");
arrayAdapter.remove(playerInList.get());
}
arrayAdapter.add(castingPlayer);
});
}
@Override
public void onRemoved(CastingPlayer castingPlayer) {
Log.i(
TAG,
"onRemoved() Removed CastingPlayer with deviceId: "
+ castingPlayer.getDeviceId());
// Remove CastingPlayer from the screen
new Handler(Looper.getMainLooper())
.post(
() -> {
final Optional<CastingPlayer> playerInList =
castingPlayerList
.stream()
.filter(node -> castingPlayer.equals(node))
.findFirst();
if (playerInList.isPresent()) {
Log.d(
TAG,
"onRemoved() Removing existing CastingPlayer entry "
+ playerInList.get().getDeviceId()
+ " in castingPlayerList list");
arrayAdapter.remove(playerInList.get());
}
});
}
};
public static DiscoveryExampleFragment newInstance() {
Log.i(TAG, "newInstance() called");
return new DiscoveryExampleFragment();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate() called");
}
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.i(TAG, "onCreateView() called");
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_matter_discovery_example, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.i(TAG, "onViewCreated() called");
matterDiscoveryMessageTextView =
getActivity().findViewById(R.id.matterDiscoveryMessageTextView);
matterDiscoveryMessageTextView.setText(
getString(R.string.matter_discovery_message_initializing_text));
matterDiscoveryErrorMessageTextView =
getActivity().findViewById(R.id.matterDiscoveryErrorTextView);
matterDiscoveryErrorMessageTextView.setText(
getString(R.string.matter_discovery_error_message_initial));
arrayAdapter = new CastingPlayerArrayAdapter(getActivity(), castingPlayerList);
final ListView list = getActivity().findViewById(R.id.castingPlayerList);
list.setAdapter(arrayAdapter);
Log.d(TAG, "onViewCreated() creating callbacks");
Button startDiscoveryButton = getView().findViewById(R.id.startDiscoveryButton);
startDiscoveryButton.setOnClickListener(
v -> {
Log.i(
TAG, "onViewCreated() startDiscoveryButton button clicked. Calling startDiscovery()");
if (!startDiscovery()) {
Log.e(TAG, "onViewCreated() startDiscovery() call Failed");
}
});
Button stopDiscoveryButton = getView().findViewById(R.id.stopDiscoveryButton);
stopDiscoveryButton.setOnClickListener(
v -> {
Log.i(TAG, "onViewCreated() stopDiscoveryButton button clicked. Calling stopDiscovery()");
stopDiscovery();
});
Button clearDiscoveryResultsButton = getView().findViewById(R.id.clearDiscoveryResultsButton);
clearDiscoveryResultsButton.setOnClickListener(
v -> {
Log.i(
TAG, "onViewCreated() clearDiscoveryResultsButton button clicked. Clearing results");
arrayAdapter.clear();
matterDiscoveryErrorMessageTextView.setText(
getString(R.string.matter_discovery_error_message_initial));
});
}
@Override
public void onResume() {
Log.i(TAG, "onResume() called");
super.onResume();
MatterError err =
matterCastingPlayerDiscovery.removeCastingPlayerChangeListener(castingPlayerChangeListener);
if (err.hasError()) {
Log.e(TAG, "onResume() removeCastingPlayerChangeListener() err: " + err);
}
if (!startDiscovery()) {
Log.e(TAG, "onResume() Warning: startDiscovery() call Failed");
}
}
@Override
public void onPause() {
super.onPause();
Log.i(TAG, "onPause() called");
}
/** Interface for notifying the host. */
public interface Callback {
/** Notifies listener of Connection Button click. */
// TODO: In following PRs. Implement CastingPlayer connection
void handleConnectionButtonClicked(CastingPlayer castingPlayer);
}
private boolean startDiscovery() {
Log.i(TAG, "startDiscovery() called");
matterDiscoveryErrorMessageTextView.setText(
getString(R.string.matter_discovery_error_message_initial));
arrayAdapter.clear();
// Add the implemented CastingPlayerChangeListener to listen to changes in the discovered
// CastingPlayers
MatterError err =
matterCastingPlayerDiscovery.addCastingPlayerChangeListener(castingPlayerChangeListener);
if (err.hasError()) {
Log.e(TAG, "startDiscovery() addCastingPlayerChangeListener() called, err Add: " + err);
matterDiscoveryErrorMessageTextView.setText(
getString(R.string.matter_discovery_error_message_stop_before_starting) + err);
return false;
}
// Start discovery
Log.i(TAG, "startDiscovery() calling CastingPlayerDiscovery.startDiscovery()");
err = matterCastingPlayerDiscovery.startDiscovery(DISCOVERY_TARGET_DEVICE_TYPE);
if (err.hasError()) {
Log.e(TAG, "startDiscovery() startDiscovery() called, err Start: " + err);
matterDiscoveryErrorMessageTextView.setText(
getString(R.string.matter_discovery_error_message_start_error) + err);
return false;
}
Log.i(TAG, "startDiscovery() started discovery");
matterDiscoveryMessageTextView.setText(
getString(R.string.matter_discovery_message_discovering_text));
return true;
}
private void stopDiscovery() {
Log.i(TAG, "stopDiscovery() called");
matterDiscoveryErrorMessageTextView.setText(
getString(R.string.matter_discovery_error_message_initial));
// Stop discovery
MatterError err = matterCastingPlayerDiscovery.stopDiscovery();
if (err.hasError()) {
Log.e(
TAG,
"stopDiscovery() MatterCastingPlayerDiscovery.stopDiscovery() called, err Stop: " + err);
matterDiscoveryErrorMessageTextView.setText(
getString(R.string.matter_discovery_error_message_stop_error) + err);
} else {
Log.d(TAG, "stopDiscovery() MatterCastingPlayerDiscovery.stopDiscovery() success");
}
matterDiscoveryMessageTextView.setText(
getString(R.string.matter_discovery_message_stopped_text));
Log.d(
TAG,
"stopDiscovery() text set to: "
+ getString(R.string.matter_discovery_message_stopped_text));
// Remove the CastingPlayerChangeListener
Log.i(TAG, "stopDiscovery() removing CastingPlayerChangeListener");
err =
matterCastingPlayerDiscovery.removeCastingPlayerChangeListener(castingPlayerChangeListener);
if (err.hasError()) {
Log.e(
TAG,
"stopDiscovery() matterCastingPlayerDiscovery.removeCastingPlayerChangeListener() called, err Remove: "
+ err);
matterDiscoveryErrorMessageTextView.setText(
getString(R.string.matter_discovery_error_message_stop_error) + err);
}
}
}
class CastingPlayerArrayAdapter extends ArrayAdapter<CastingPlayer> {
private final List<CastingPlayer> playerList;
private final Context context;
private LayoutInflater inflater;
private static final String TAG = CastingPlayerArrayAdapter.class.getSimpleName();
public CastingPlayerArrayAdapter(Context context, List<CastingPlayer> playerList) {
super(context, 0, playerList);
Log.i(TAG, "CastingPlayerArrayAdapter() constructor called");
this.context = context;
this.playerList = playerList;
inflater = (LayoutInflater.from(context));
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
view = inflater.inflate(R.layout.commissionable_player_list_item, null);
String buttonText = getCastingPlayerButtonText(playerList.get(i));
Button playerDescription = view.findViewById(R.id.commissionable_player_description);
playerDescription.setText(buttonText);
View.OnClickListener clickListener =
v -> {
CastingPlayer castingPlayer = playerList.get(i);
Log.d(
TAG,
"OnClickListener.onClick() called for CastingPlayer with deviceId: "
+ castingPlayer.getDeviceId());
DiscoveryExampleFragment.Callback onClickCallback =
(DiscoveryExampleFragment.Callback) context;
onClickCallback.handleConnectionButtonClicked(castingPlayer);
};
playerDescription.setOnClickListener(clickListener);
return view;
}
private String getCastingPlayerButtonText(CastingPlayer player) {
String main = player.getDeviceName() != null ? player.getDeviceName() : "";
String aux = "" + (player.getDeviceId() != null ? "Device ID: " + player.getDeviceId() : "");
aux +=
player.getProductId() > 0
? (aux.isEmpty() ? "" : ", ") + "Product ID: " + player.getProductId()
: "";
aux +=
player.getVendorId() > 0
? (aux.isEmpty() ? "" : ", ") + "Vendor ID: " + player.getVendorId()
: "";
aux +=
player.getDeviceType() > 0
? (aux.isEmpty() ? "" : ", ") + "Device Type: " + player.getDeviceType()
: "";
aux += (aux.isEmpty() ? "" : ", ") + "Resolved IP?: " + (player.getIpAddresses().size() > 0);
aux +=
(aux.isEmpty() ? "" : ", ")
+ "Supports Commissioner Generated Passcode: "
+ (player.getSupportsCommissionerGeneratedPasscode());
aux = aux.isEmpty() ? aux : "\n" + aux;
return main + aux;
}
}