Skip to content

Commit

Permalink
Android OnOff to java (#16525)
Browse files Browse the repository at this point in the history
* add onoff mgr and pass build

* add test code to set onoff

* fix restyled-io and ci errors

* fix PR comment

* fix restyled-io and ci errors

* fix PR comment

* add level mgr

* fix restyled-io and ci errors

* fix PR comment

* fix restyled-io and ci errors

* fix kEmberInvalidEndpointIndex naming as PR comment

* fix restyled-io and ci errors
  • Loading branch information
xylophone21 authored and pull[bot] committed Oct 24, 2023
1 parent d6d4620 commit 5782004
Show file tree
Hide file tree
Showing 18 changed files with 585 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import chip.setuppayload.DiscoveryCapability;
Expand Down Expand Up @@ -33,6 +34,29 @@ public void onClick(View view) {
MatterServant.get().restart();
}
});
findViewById(R.id.OnOffBtn)
.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
MatterServant.get().toggleOnOff();
}
});

SeekBar sb = findViewById(R.id.seekBar);
sb.setOnSeekBarChangeListener(
new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
MatterServant.get().updateLevel(i);
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});

// TODO: Get these parameters from PreferencesConfigurationManager
HashSet<DiscoveryCapability> discoveryCapabilities = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@
import com.tcl.chip.tvapp.ContentLaunchManagerStub;
import com.tcl.chip.tvapp.DACProviderStub;
import com.tcl.chip.tvapp.KeypadInputManagerStub;
import com.tcl.chip.tvapp.LevelManagerStub;
import com.tcl.chip.tvapp.LowPowerManagerStub;
import com.tcl.chip.tvapp.MediaInputManagerStub;
import com.tcl.chip.tvapp.MediaPlaybackManagerStub;
import com.tcl.chip.tvapp.OnOffManagerStub;
import com.tcl.chip.tvapp.TvApp;
import com.tcl.chip.tvapp.WakeOnLanManagerStub;

Expand All @@ -44,6 +46,10 @@ public class MatterServant {
public int testDiscriminator = 0xF00;

private ChipAppServer chipAppServer;
private TvApp mTvApp;
private boolean mIsOn = true;
private int mOnOffEndpoint;
private int mLevelEndpoint;

private MatterServant() {}

Expand All @@ -61,7 +67,7 @@ public void init(@NonNull Context context) {
// then chipPlatform to prepare platform
// then TvApp.postInit to init app which needs platform
// then start ChipAppServer
TvApp tvApp =
mTvApp =
new TvApp(
(app, clusterId, endpoint) -> {
switch (clusterId) {
Expand All @@ -86,9 +92,17 @@ public void init(@NonNull Context context) {
case Clusters.ClusterId_Channel:
app.setChannelManager(endpoint, new ChannelManagerStub(endpoint));
break;
case Clusters.ClusterId_OnOff:
mOnOffEndpoint = endpoint;
app.setOnOffManager(endpoint, new OnOffManagerStub(endpoint));
break;
case Clusters.ClusterId_LevelControl:
mLevelEndpoint = endpoint;
app.setLevelManager(endpoint, new LevelManagerStub(endpoint));
break;
}
});
tvApp.setDACProvider(new DACProviderStub());
mTvApp.setDACProvider(new DACProviderStub());

Context applicationContext = context.getApplicationContext();
AndroidChipPlatform chipPlatform =
Expand All @@ -103,7 +117,7 @@ public void init(@NonNull Context context) {
chipPlatform.updateCommissionableDataProviderData(
null, null, 0, testSetupPasscode, testDiscriminator);

tvApp.postInit();
mTvApp.postInit();

chipAppServer = new ChipAppServer();
chipAppServer.startApp();
Expand All @@ -113,4 +127,13 @@ public void restart() {
chipAppServer.stopApp();
chipAppServer.startApp();
}

public void toggleOnOff() {
mTvApp.setOnOff(mOnOffEndpoint, mIsOn);
mIsOn = !mIsOn;
}

public void updateLevel(int value) {
mTvApp.setCurrentLevel(mLevelEndpoint, value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,25 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

<Button
android:id="@+id/OnOffBtn"
android:text="OnOff"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/resetBtn"
android:layout_marginTop="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>

<SeekBar
android:id="@+id/seekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/OnOffBtn"
android:layout_marginTop="20dp"
android:maxHeight="2dp"
android:minHeight="2dp"
android:max="100"
/>

</androidx.constraintlayout.widget.ConstraintLayout>
10 changes: 9 additions & 1 deletion examples/tv-app/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,30 @@ shared_library("jni") {
"include/application-launcher/ApplicationLauncherManager.h",
"include/audio-output/AudioOutputManager.cpp",
"include/audio-output/AudioOutputManager.h",
"include/cluster-change-attribute.cpp",
"include/cluster-init.cpp",
"include/endpoint-configuration/EndpointConfigurationStorage.cpp",
"include/endpoint-configuration/EndpointConfigurationStorage.h",
"include/target-navigator/TargetNavigatorManager.cpp",
"include/target-navigator/TargetNavigatorManager.h",
"java/ChannelManager.cpp",
"java/ChannelManager.h",
"java/ClusterChangeAttribute.cpp",
"java/ContentLauncherManager.cpp",
"java/ContentLauncherManager.h",
"java/JNIDACProvider.cpp",
"java/JNIDACProvider.h",
"java/KeypadInputManager.cpp",
"java/KeypadInputManager.h",
"java/LevelManager.cpp",
"java/LevelManager.h",
"java/LowPowerManager.cpp",
"java/LowPowerManager.h",
"java/MediaInputManager.cpp",
"java/MediaInputManager.h",
"java/MediaPlaybackManager.cpp",
"java/MediaPlaybackManager.h",
"java/OnOffManager.cpp",
"java/OnOffManager.h",
"java/TVApp-JNI.cpp",
"java/WakeOnLanManager.cpp",
"java/WakeOnLanManager.h",
Expand Down Expand Up @@ -99,6 +103,8 @@ android_library("java") {
"java/src/com/tcl/chip/tvapp/DACProviderStub.java",
"java/src/com/tcl/chip/tvapp/KeypadInputManager.java",
"java/src/com/tcl/chip/tvapp/KeypadInputManagerStub.java",
"java/src/com/tcl/chip/tvapp/LevelManager.java",
"java/src/com/tcl/chip/tvapp/LevelManagerStub.java",
"java/src/com/tcl/chip/tvapp/LowPowerManager.java",
"java/src/com/tcl/chip/tvapp/LowPowerManagerStub.java",
"java/src/com/tcl/chip/tvapp/MediaInputInfo.java",
Expand All @@ -107,6 +113,8 @@ android_library("java") {
"java/src/com/tcl/chip/tvapp/MediaPlaybackManager.java",
"java/src/com/tcl/chip/tvapp/MediaPlaybackManagerStub.java",
"java/src/com/tcl/chip/tvapp/MediaPlaybackPosition.java",
"java/src/com/tcl/chip/tvapp/OnOffManager.java",
"java/src/com/tcl/chip/tvapp/OnOffManagerStub.java",
"java/src/com/tcl/chip/tvapp/TvApp.java",
"java/src/com/tcl/chip/tvapp/TvAppCallback.java",
"java/src/com/tcl/chip/tvapp/WakeOnLanManager.java",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
* limitations under the License.
*/

#include "LevelManager.h"
#include "OnOffManager.h"
#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/ConcreteAttributePath.h>
Expand All @@ -24,44 +26,24 @@
using namespace chip;
using namespace ::chip::app::Clusters;

enum TvCommand
void MatterPostAttributeChangeCallback(const app::ConcreteAttributePath & attributePath, uint8_t mask, uint8_t type, uint16_t size,
uint8_t * value)
{
PowerToggle,
MuteToggle
};

void runTvCommand(TvCommand command)
{
switch (command)
if (attributePath.mClusterId == OnOff::Id && attributePath.mAttributeId == OnOff::Attributes::OnOff::Id)
{
case PowerToggle:
// TODO: Insert your code here to send power toggle command
break;
case MuteToggle:
// TODO: Insert your code here to send mute toggle command
break;
bool onoff = static_cast<bool>(*value);

default:
break;
}
}
ChipLogProgress(Zcl, "Received on/off command endpoint %d value = %d", static_cast<int>(attributePath.mEndpointId), onoff);

void MatterAfPostAttributeChangeCallback(const app::ConcreteAttributePath & attributePath, uint8_t mask, uint8_t type,
uint16_t size, uint8_t * value)
{
if (attributePath.mClusterId == OnOff::Id && attributePath.mAttributeId == OnOff::Attributes::OnOff::Id)
OnOffManager().PostOnOffChanged(attributePath.mEndpointId, onoff);
}
else if (attributePath.mClusterId == LevelControl::Id &&
attributePath.mAttributeId == LevelControl::Attributes::CurrentLevel::Id)
{
ChipLogProgress(Zcl, "Received on/off command for cluster id: " ChipLogFormatMEI, ChipLogValueMEI(OnOff::Id));
uint8_t level = *value;

ChipLogProgress(Zcl, "Received level command endpoint %d value = %d", static_cast<int>(attributePath.mEndpointId), level);

if (attributePath.mEndpointId == 0)
{
ChipLogProgress(Zcl, "Execute POWER_TOGGLE");
runTvCommand(PowerToggle);
}
else if (attributePath.mEndpointId == 1)
{
ChipLogProgress(Zcl, "Execute MUTE_TOGGLE");
runTvCommand(MuteToggle);
}
LevelManager().PostLevelChanged(attributePath.mEndpointId, level);
}
}
126 changes: 126 additions & 0 deletions examples/tv-app/android/java/LevelManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/**
*
* Copyright (c) 2022 Project CHIP Authors
*
* 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.
*/
#include "LevelManager.h"
#include "TvApp-JNI.h"
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/util/af.h>
#include <jni.h>
#include <lib/support/CHIPJNIError.h>
#include <lib/support/JniReferences.h>
#include <lib/support/JniTypeWrappers.h>

using namespace chip;

static constexpr size_t kLevelManagerTableSize = EMBER_AF_LEVEL_CONTROL_CLUSTER_SERVER_ENDPOINT_COUNT;

namespace {

LevelManager * gLevelManagerTable[kLevelManagerTableSize] = { nullptr };

}

void emberAfLevelControlClusterInitCallback(EndpointId endpoint)
{
ChipLogProgress(Zcl, "TV Android App::Level::PostClusterInit");
TvAppJNIMgr().PostClusterInit(chip::app::Clusters::LevelControl::Id, endpoint);
}

void LevelManager::NewManager(jint endpoint, jobject manager)
{
ChipLogProgress(Zcl, "TV Android App: LevelManager::NewManager");
uint16_t ep = emberAfFindClusterServerEndpointIndex(static_cast<chip::EndpointId>(endpoint), app::Clusters::LevelControl::Id);
VerifyOrReturn(ep != kEmberInvalidEndpointIndex && ep < kLevelManagerTableSize,
ChipLogError(Zcl, "TV Android App::Level::NewManager: endpoint %d not found", endpoint));

VerifyOrReturn(gLevelManagerTable[ep] == nullptr,
ChipLogError(Zcl, "TV Android App::Level::NewManager: endpoint %d already has a manager", endpoint));
LevelManager * mgr = new LevelManager();
CHIP_ERROR err = mgr->InitializeWithObjects(manager);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Zcl, "TV Android App::Level::NewManager: failed to initialize manager for endpoint %d", endpoint);
delete mgr;
}
else
{
gLevelManagerTable[ep] = mgr;
}
}

LevelManager * GetLevelManager(EndpointId endpoint)
{
uint16_t ep = emberAfFindClusterServerEndpointIndex(endpoint, app::Clusters::LevelControl::Id);
return ((ep == kEmberInvalidEndpointIndex || ep >= kLevelManagerTableSize) ? nullptr : gLevelManagerTable[ep]);
}

void LevelManager::PostLevelChanged(chip::EndpointId endpoint, uint8_t value)
{
ChipLogProgress(Zcl, "TV Android App: LevelManager::PostLevelChanged");
LevelManager * mgr = GetLevelManager(endpoint);
VerifyOrReturn(mgr != nullptr, ChipLogError(Zcl, "LevelManager null"));

mgr->HandleLevelChanged(value);
}

jboolean LevelManager::SetLevel(jint endpoint, jint value)
{
EmberAfStatus status = app::Clusters::LevelControl::Attributes::CurrentLevel::Set(static_cast<chip::EndpointId>(endpoint),
static_cast<uint8_t>(value));
return status == EMBER_ZCL_STATUS_SUCCESS;
}

CHIP_ERROR LevelManager::InitializeWithObjects(jobject managerObject)
{
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
VerifyOrReturnLogError(env != nullptr, CHIP_ERROR_INCORRECT_STATE);

mLevelManagerObject = env->NewGlobalRef(managerObject);
VerifyOrReturnLogError(mLevelManagerObject != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

jclass LevelManagerClass = env->GetObjectClass(managerObject);
VerifyOrReturnLogError(LevelManagerClass != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

mHandleLevelChangedMethod = env->GetMethodID(LevelManagerClass, "HandleLevelChanged", "(I)V");
if (mHandleLevelChangedMethod == nullptr)
{
ChipLogError(Zcl, "Failed to access LevelManager 'HandleLevelChanged' method");
env->ExceptionClear();
return CHIP_ERROR_INVALID_ARGUMENT;
}

return CHIP_NO_ERROR;
}

void LevelManager::HandleLevelChanged(uint8_t value)
{
ChipLogProgress(Zcl, "LevelManager::HandleLevelChanged");

JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
VerifyOrReturn(env != NULL, ChipLogProgress(Zcl, "env null"));
VerifyOrReturn(mLevelManagerObject != nullptr, ChipLogProgress(Zcl, "mLevelManagerObject null"));
VerifyOrReturn(mHandleLevelChangedMethod != nullptr, ChipLogProgress(Zcl, "mHandleLevelChangedMethod null"));

env->ExceptionClear();
env->CallVoidMethod(mLevelManagerObject, mHandleLevelChangedMethod, static_cast<jint>(value));
if (env->ExceptionCheck())
{
ChipLogError(AppServer, "Java exception in LevelManager::HandleLevelChanged");
env->ExceptionDescribe();
env->ExceptionClear();
}
}
Loading

0 comments on commit 5782004

Please sign in to comment.