[Huawei Developers] Freemind R:
More articles like this, you can visit HUAWEI Developer Forum and Medium.

[IMG="https://img.xda-cdn.com/1VML4RTNvfWgHRoDEujFWXktTLA=/https%3A%2F%2Fcommunityfile-dre.op.hicloud.com%2FFileServer%2FgetFile%2Fcmtybbs%2F001%2F768%2F541%2F2640091000001768541.20200610060136.17559478831923220536215973422938%3A50510618025057%3A2800%3A6C996E276C70FD1756AE12972E525ECDB7C51531653C065518FB8599C84A4046.jpg"]https://img.xda-cdn.com/1VML4RTNvfWgHRoDEujFWXktTLA=/https%3A%2F%2Fcommunityfile-dre.op.hicloud.com%2FFileServer%2FgetFile%2Fcmtybbs%2F001%2F768%2F541%2F2640091000001768541.20200610060136.17559478831923220536215973422938%3A50510618025057%3A2800%3A6C996E276C70FD1756AE12972E525ECDB7C51531653C065518FB8599C84A4046.jpg[/IMG]​

https://forums.developer.huawei.com/forumPortal/en/home

In this article, We will implement the Huawei Share Kit SDK and complete our demo application.

In the previous article, we have learned about Share Kit introduction and created project. So let’s start our implementation.

I will represent the functionality of Share Kit in a simple way with a working application and give a demo.

Before start developing the application we must have the following requirement.

Hardware Requirements

1. A computer (desktop or laptop) that runs Windows 7 or Windows 10

2. A Huawei phone (with the USB cable), which is used for debugging

3. A third-party Android device, which is used for debugging

Software Requirements

1. JDK 1.8 or later

2. Android API (level 26 or higher)

3. EMUI 10.0 or later

Let’s start the development:

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610155658.60845915506749437594190956655056:50510618065012:2800:8A04C793800218387CB088200353BC731177C27318342276CC8B5F06CA0F9A3E.gif"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610155658.60845915506749437594190956655056:50510618065012:2800:8A04C793800218387CB088200353BC731177C27318342276CC8B5F06CA0F9A3E.gif[/IMG]​

1. Add Share Kit SDK in project:

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610155748.30324886932825057847277937809482:50510618065012:2800:1D9F7E6545439665D19F7AC2995E37982F7F68660A3C4FCB9A39089CA8F6A997.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610155748.30324886932825057847277937809482:50510618065012:2800:1D9F7E6545439665D19F7AC2995E37982F7F68660A3C4FCB9A39089CA8F6A997.png[/IMG]​

2. We need to add the code repository to the project root directory gradle.

maven {
url 'http://developer.huawei.com/repo/'
}

3. We need to add the following dependencies in our app gradle.

dependencies {
implementation files('libs/sharekit-1.0.1.300.aar')
implementation 'com.android.support:support-annotations:28.0.0'
implementation 'com.android.support:localbroadcastmanager:28.0.0'
implementation 'com.android.support:support-compat:28.0.0'
implementation 'com.google.guava:guava:24.1-android'
}

Note: You need to raise a ticket to get Share Kit SDK “sharekit-1.0.300.aar” file

Click on the below link and raise your ticket.

https://developer.huawei.com/consumer/en/support/feedback/#/

4. I have created following package and resource file:

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610155827.62390056679787836450939404328528:50510618065012:2800:B68A2CF48A6D3B0FA0F04D43DCC9E16A0A8599CB49E251068529FD964F4EEFB6.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610155827.62390056679787836450939404328528:50510618065012:2800:B68A2CF48A6D3B0FA0F04D43DCC9E16A0A8599CB49E251068529FD964F4EEFB6.png[/IMG]​

5. I have mentioned all activities in manifest file:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hms.myshare">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">

<activity
android:name=".SplashScreen"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity
android:name=".SearchingActivity"
android:configChanges="orientation|keyboardHidden|screenSize"/>

<activity
android:name=".ReceiveActivity"
android:configChanges="orientation|keyboardHidden|screenSize"/>
</application>
</manifest>

Let’s create an awesome User Interface:

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610155859.52093777069818817848919055175194:50510618065012:2800:15D9E03E6C46AC810DE9B5DB2BA8B88C3CFDF0ADF43670A01F41F5B559F8D238.gif"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610155859.52093777069818817848919055175194:50510618065012:2800:15D9E03E6C46AC810DE9B5DB2BA8B88C3CFDF0ADF43670A01F41F5B559F8D238.gif[/IMG]​

1. I have created a wave ripple effect which will help to find the device from a UI perspective.

I have created a SearchingView.java class:

public class SearchingView extends RelativeLayout {

private static final int DEFAULT_RIPPLE_COUNT=6;
private static final int DEFAULT_DURATION_TIME=3000;
private static final float DEFAULT_SCALE=6.0f;
private static final int DEFAULT_FILL_TYPE=0;

private int rippleColor;
private float rippleStrokeWidth;
private float rippleRadius;
private int rippleDurationTime;
private int rippleAmount;
private int rippleDelay;
private float rippleScale;
private int rippleType;
private Paint paint;
private boolean animationRunning=false;
private AnimatorSet animatorSet;
private ArrayList<Animator> animatorList;
private LayoutParams rippleParams;
private ArrayList<RippleView> rippleViewList=new ArrayList<RippleView>();

public SearchingView(Context context) {
super(context);
}

public SearchingView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}

public SearchingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}

private void init(final Context context, final AttributeSet attrs) {
if (isInEditMode())
return;

if (null == attrs) {
throw new IllegalArgumentException("Attributes should be provided to this view,");
}

final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RippleBackground);
rippleColor=typedArray.getColor(R.styleable.RippleBackground_rb_color, getResources().getColor(R.color.rippelColor));
rippleStrokeWidth=typedArray.getDimension(R.styleable.RippleBackground_rb_strokeWidth, getResources().getDimension(R.dimen.rippleStrokeWidth));
rippleRadius=typedArray.getDimension(R.styleable.RippleBackground_rb_radius,getResources().getDimension(R.dimen.rippleRadius));
rippleDurationTime=typedArray.getInt(R.styleable.RippleBackground_rb_duration,DEFAULT_DURATION_TIME);
rippleAmount=typedArray.getInt(R.styleable.RippleBackground_rb_rippleAmount,DEFAULT_RIPPLE_COUNT);
rippleScale=typedArray.getFloat(R.styleable.RippleBackground_rb_scale,DEFAULT_SCALE);
rippleType=typedArray.getInt(R.styleable.RippleBackground_rb_type,DEFAULT_FILL_TYPE);
typedArray.recycle();

rippleDelay=rippleDurationTime/rippleAmount;

paint = new Paint();
paint.setAntiAlias(true);
if(rippleType==DEFAULT_FILL_TYPE){
rippleStrokeWidth=0;
paint.setStyle(Paint.Style.FILL);
}else
paint.setStyle(Paint.Style.STROKE);
paint.setColor(rippleColor);

rippleParams=new LayoutParams((int)(2*(rippleRadius+rippleStrokeWidth)),(int)(2*(rippleRadius+rippleStrokeWidth)));
rippleParams.addRule(CENTER_IN_PARENT, TRUE);

animatorSet = new AnimatorSet();
animatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
animatorList=new ArrayList<Animator>();

for(int i=0;i<rippleAmount;i++){
RippleView rippleView=new RippleView(getContext());
addView(rippleView,rippleParams);
rippleViewList.add(rippleView);
final ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(rippleView, "ScaleX", 1.0f, rippleScale);
scaleXAnimator.setRepeatCount(ObjectAnimator.INFINITE);
scaleXAnimator.setRepeatMode(ObjectAnimator.RESTART);
scaleXAnimator.setStartDelay(i * rippleDelay);
scaleXAnimator.setDuration(rippleDurationTime);
animatorList.add(scaleXAnimator);
final ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(rippleView, "ScaleY", 1.0f, rippleScale);
scaleYAnimator.setRepeatCount(ObjectAnimator.INFINITE);
scaleYAnimator.setRepeatMode(ObjectAnimator.RESTART);
scaleYAnimator.setStartDelay(i * rippleDelay);
scaleYAnimator.setDuration(rippleDurationTime);
animatorList.add(scaleYAnimator);
final ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(rippleView, "Alpha", 1.0f, 0f);
alphaAnimator.setRepeatCount(ObjectAnimator.INFINITE);
alphaAnimator.setRepeatMode(ObjectAnimator.RESTART);
alphaAnimator.setStartDelay(i * rippleDelay);
alphaAnimator.setDuration(rippleDurationTime);
animatorList.add(alphaAnimator);
}

animatorSet.playTogether(animatorList);
}

private class RippleView extends View {

public RippleView(Context context) {
super(context);
this.setVisibility(View.INVISIBLE);
}

@Override
protected void onDraw(Canvas canvas) {
int radius=(Math.min(getWidth(),getHeight()))/2;
canvas.drawCircle(radius,radius,radius-rippleStrokeWidth,paint);
}
}

public void startRippleAnimation(){
if(!isRippleAnimationRunning()){
for(RippleView rippleView:rippleViewList){
rippleView.setVisibility(VISIBLE);
}
animatorSet.start();
animationRunning=true;
}
}

public void stopRippleAnimation(){
if(isRippleAnimationRunning()){
animatorSet.end();
animationRunning=false;
}
}

public boolean isRippleAnimationRunning(){
return animationRunning;
}

Let’s see the implementation of this custom view inside xml layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:background="@drawable/background"
android:layout_height="match_parent">

<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center">

<com.hms.myshare.view.SearchingView
android:id="@+id/searching"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:rb_color="@android:color/white"
app:rb_duration="3000"
app:rb_radius="40dp"
app:rb_rippleAmount="6"
app:rb_scale="5">

<ImageView
android:id="@+id/img_logo"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerInParent="true"
android:src="@drawable/log" />

</com.hms.myshare.view.SearchingView>

</RelativeLayout>

<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:textColor="@android:color/white"
android:textSize="28sp"
android:gravity="center"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="Huawei Share Kit"
android:id="@+id/appCompatTextView2" />

</LinearLayout>

Let’ see the output of this view:

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610061238.79225434580714349935517331734317:50510618065012:2800:566384DF5C9626E18A826B5048A61C04F8F032EDF625D7D983EE35647D5F307B.gif"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610061238.79225434580714349935517331734317:50510618065012:2800:566384DF5C9626E18A826B5048A61C04F8F032EDF625D7D983EE35647D5F307B.gif[/IMG]​

Let’s implement Search device and Send Data:

· We have implemented this functionality inside SearchingActivity class.

We need to perform the following operation in order to implement sending data to found device.

1. We need to instantiate SDK manager class i.e. ShareKitManager with current context of Activity inside the oncreate method.

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

binding = DataBindingUtil.setContentView(this, R.layout.searching_activity);
shareKitManager = new ShareKitManager(this);

2. Add callback IShareKitInitCallback to initialize the ShareKitManager class.

IShareKitInitCallback initCallback = isSuccess -> {
Log.i(TAG, "share kit init result:" + isSuccess);
if (isSuccess) {
binding.txtError.setText(getString(R.string.sharekit_init_finish));
} else {
binding.txtError.setText(getString(R.string.sharekit_init_failed));
}
};
shareKitManager.init(initCallback);

3. Register the ShareKitManager with IWidgetCallback:

private IWidgetCallback callback = new IWidgetCallback.Stub() {
@Override
public synchronized void onDeviceFound(NearByDeviceEx nearByDeviceEx) {
String deviceId = nearByDeviceEx.getCommonDeviceId();
if (deviceId == null) {
Log.e(TAG, "onDeviceFound: deviceId is null");
return;
}
Log.i(TAG, "onDeviceFound: " + deviceId + ", btName: " + nearByDeviceEx.getBtName());
synchronized (lock) {
deviceMap.put(deviceId, nearByDeviceEx);
foundTimeMap.put(deviceId, format.format(new Date()));
updateDeviceList();
}
}

@Override
public void onDeviceDisappeared(NearByDeviceEx nearByDeviceEx) {
String deviceId = nearByDeviceEx.getCommonDeviceId();
if (deviceId == null) {
Log.e(TAG, "onDeviceDisappeared: deviceId is null");
return;
}
Log.i(TAG, "onDeviceDisappeared: " + deviceId + ", btName: " + nearByDeviceEx.getBtName());
synchronized (lock) {
deviceMap.remove(deviceId);
foundTimeMap.remove(deviceId);
updateDeviceList();
}
}

@Override
public void onTransStateChange(NearByDeviceEx nearByDeviceEx, int state, int stateValue) {
Log.i(TAG, "trans state:" + state + " value:" + stateValue);
String stateDesc = "";
switch (state) {
case STATE_PROGRESS:
stateDesc = getString(R.string.sharekit_send_progress, stateValue);
break;
case STATE_SUCCESS:
stateDesc = getString(R.string.sharekit_send_finish);
break;
case STATE_STATUS:
stateDesc = getString(R.string.sharekit_state_chg, translateStateValue(stateValue));
break;
case STATE_ERROR:
stateDesc = getString(R.string.sharekit_send_error, translateErrorValue(stateValue));
showError(getString(R.string.sharekit_send_error, translateErrorValue(stateValue)));
break;
default:
break;
}
// showToast(stateDesc);
}

@Override
public void onEnableStatusChanged() {
int status = shareKitManager.getShareStatus();
Log.i(TAG, "sharekit ability current status:" + status);
}
};

We need to pass this callback to Register api.

shareKitManager.registerCallback(callback);

4. Start searching device using Discorvey api.

shareKitManager.startDiscovery();

5. If you found the device successfully we need to call the ShareBean api for send the data.

private void doSendText() {
String text = binding.sharetext.getText().toString();
ShareBean shareBean = new ShareBean(text);
doSend(destDevice, shareBean);
}

Followed by doSend() method:

private void doSend(String deviceName, ShareBean shareBean) {
List<NearByDeviceEx> processingDevices = shareKitManager.getDeviceList();
for (NearByDeviceEx device : processingDevices) {
if (deviceName.equals(device.getBtName())) {
return;
}
}
synchronized (lock) {
for (NearByDeviceEx device : deviceMap.values()) {
if (deviceName.equals(device.getBtName())) {
shareKitManager.doSend(device, shareBean);
}
}
}
}

Let’s implement Receive data functionality:

· We have implemented this functionality inside ReceivingActivity.

· We need to enable wifi in Huawei device which receive the socket connection request from sender device.

· So we need to initialize the ShareKitManager inside this activity oncreate method.

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

binding = DataBindingUtil.setContentView(this, R.layout.receiver_activity);
binding.searching.startRippleAnimation();

shareKitManager = new ShareKitManager(this);
IShareKitInitCallback initCallback = isSuccess -> {
Log.i(TAG, "share kit init result:" + isSuccess);
};
shareKitManager.init(initCallback);
shareKitManager.enable();
}

Android device (Sender):

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610060859.36711468348519386917658415497866:50510618065012:2800:A7F8378E1692A2B59B27BFBBE9DFADB1F3D0BDEC2101FF7CB4B6290B79222195.gif"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610060859.36711468348519386917658415497866:50510618065012:2800:A7F8378E1692A2B59B27BFBBE9DFADB1F3D0BDEC2101FF7CB4B6290B79222195.gif[/IMG]

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610060950.26238476688476791442444861983727:50510618065012:2800:32C174FC21937807C10F95508D17E384968D83CBCF4BE179729B876FDE97C0A5.gif"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610060950.26238476688476791442444861983727:50510618065012:2800:32C174FC21937807C10F95508D17E384968D83CBCF4BE179729B876FDE97C0A5.gif[/IMG]

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610061107.78337866955906157613763559605502:50510618065012:2800:B86944E435EC216935811183C5EF50BCC4B30BBC3EF0352F9052932BF8AED4C2.gif"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610061107.78337866955906157613763559605502:50510618065012:2800:B86944E435EC216935811183C5EF50BCC4B30BBC3EF0352F9052932BF8AED4C2.gif[/IMG]​

Huawei device (Receiver):

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610061238.79225434580714349935517331734317:50510618065012:2800:566384DF5C9626E18A826B5048A61C04F8F032EDF625D7D983EE35647D5F307B.gif"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610061238.79225434580714349935517331734317:50510618065012:2800:566384DF5C9626E18A826B5048A61C04F8F032EDF625D7D983EE35647D5F307B.gif[/IMG]

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610061238.69594597845046422332490239442843:50510618065012:2800:EBFF508363D137D3F1BD22148463634D96D78E06BB6A9A6AD8778BF4DDB9EF5B.gif"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610061238.69594597845046422332490239442843:50510618065012:2800:EBFF508363D137D3F1BD22148463634D96D78E06BB6A9A6AD8778BF4DDB9EF5B.gif[/IMG]

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610061238.06531090303532743198258151392412:50510618065012:2800:2C1F13983D66E3B6C05414C284BF4BCB73EDE68961686180CDEF54470E49C087.gif"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/768/541/2640091000001768541.20200610061238.06531090303532743198258151392412:50510618065012:2800:2C1F13983D66E3B6C05414C284BF4BCB73EDE68961686180CDEF54470E49C087.gif[/IMG]​

If you have any doubts or queries. Please leave your valuable comment or post your doubts in HUAWEI Developer Forum.