Original Post By Lithid-cm . Quoted Here so some can Learn
lithid-cm said:
This is just going to be a quick rundown on what do to add new toggles to android new QuickSettings system. This will take place in SystemUI.
Custom QuickSettings Toggles
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Path: frameworks/base/packages/SystemUI
Files:
src/com/android/systemui/statusbar/phone/QuickSettings.java
There are two options when creating a toggle.
addSystemTiles:380 - Static tiles with useful information.
addTemporaryTiles:571 - This type of tile will get removed without activity, for example, the alarm quick setting is a temp tile.
I used SystemTiles
Code:
// CpuInfo tile
QuickSettingsTileView cpuInfoTile = (QuickSettingsTileView)
inflater.inflate(R.layout.quick_settings_tile, parent, false);
cpuInfoTile.setContent(R.layout.quick_settings_tile_cpuinfo, inflater);
cpuInfoTile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startSettingsActivity(Intent.ACTION_POWER_USAGE_SUMMARY);
}
});
mModel.addCpuInfoTile(cpuInfoTile, new QuickSettingsModel.RefreshCallback() {
@Override
public void refreshView(QuickSettingsTileView view, State state) {
ImageView iv = (ImageView) view.findViewById(R.id.cpuinfo_image);
TextView tva = (TextView) view.findViewById(R.id.cpuinfoa_textview);
TextView tvb = (TextView) view.findViewById(R.id.cpuinfob_textview);
Drawable d = mContext.getResources().getDrawable(R.drawable.ic_settings_performance);
String GOV = fileReadOneLine(GOV_FILE);
String FREQ = fileReadOneLine(SCALE_CUR_FILE);
iv.setImageDrawable(d);
tva.setText(GOV);
tvb.setText(FREQ);
view.setContentDescription(
mContext.getString(R.string.accessibility_quick_settings_cpuinfo, GOV));
}
});
parent.addView(cpuInfoTile);
src/com/android/systemui/statusbar/phone/QuickSettingsModel.java:174
This is needed for the widget inside the toggle to get updated. You can view other definitions in here to update various states.
Code:
private QuickSettingsTileView mCpuInfoTile;
private RefreshCallback mCpuInfoCallback;
private State mCpuInfoState = new State();
res/layout/quick_settings_tile_cpuinfo.xml
This is where we create the layout of the tile and call it from java.
Code:
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2012 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/cpuinfo_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingBottom="10dp"
/>
<TextView
style="@style/TextAppearance.QuickSettings.TileView"
android:id="@+id/cpuinfoa_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#287AA9"
android:gravity="center"
/>
<TextView
style="@style/TextAppearance.QuickSettings.TileView"
android:id="@+id/cpuinfob_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#287AA9"
android:gravity="center"
/>
</LinearLayout>
res/values/strings.xml
Needed to setContentDescription()
Code:
<string name="accessibility_quick_settings_cpuinfo">CpuInfo <xliff:g id="meminfo" example="CpuInfo">%s</xliff:g>.</string>
I know this is a very general overview, but the actuality is there is so much that can be done with this, it would be hard to go into extreme detail. Would be better to just simply leave that stuff for questions in this thread.
If you want to know more, please just ask. Lets make android OURS!
Click to expand...
Click to collapse
Related
Here is an official tutorial for how to design a theme for "Helicopter Game" which is available in the market.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Step 1 - create a new android project using the following settings:
build target 2.2
create activity: main
min sdk version 4
Step 2 - create a new android xml in res/values called theme_config.xml
Fill in these details
Code:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="red">0</integer>
<integer name="green">186</integer>
<integer name="blue">255</integer>
<integer name="fred">0</integer>
<integer name="fgreen">0</integer>
<integer name="fblue">0</integer>
<bool name="randomSmoke">false</bool>
</resources>
red, blue, and green are for the background color
fred, fgreen, and fblue are for the font color
randomSmoke is a boolean (if true it will rotate the smoke particles randomly - set to true by default)
Step 3 - Edit res/values/strings.xml and add your app name, so it should look something like this:
Code:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, main!</string>
<string name="app_name">HGTheme: Shark</string>
</resources>
Step 5 - Edit your AndroidManifest.xml file, add in the following intent filters
Code:
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".main"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="com.fkarim.helicopter.THEMES" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="com.fkarim.helicopter.ACTION_PICK_ICON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
Step 6 - make your images and put them in res/drawable
you need the following images:
cavewalls.png (240 x 240)
roof.png(240 x 240) - optional if you want a different colored cave ceiling
copter.png (around 120 x 50)
obstacles.png (50 x 100)
smoke.png (32 x 32)
Step 7 - publish your app
If you need some help for how to publish an app check out this article:
http://www.devx.com/wireless/Article/39972/1954
make sure the name starts with "HGTheme :" (and should have "helicopter game theme" in the description for now) so its easy for people to search for it in the market.
Thanks for reading the tutorial. I will be posting an example theme soon with the source code also.
I've released two themes in the market. Here is the packaged source of the shark theme if anyone would like to take a look.
I have added two other features, the ability to prevent the smoke from being rotated and having a different image for the roof and floor of the cave. If anyone is interested in designing a theme, please let me know if you need help.
Hey guys, I was wondering if someone could help me out with something... I am a "developer" over in the Samsung Continuum thread, and I am on the verge of a breakthrough. (Background info for Samsung Continuum: Samsung Page: we are on Froyo 2.2.2...) I made it so the ticker could rotate depending on what orientation your phone is in (which wasn't included in stock). However, I am having difficulties in modifying the default portrait layout so that it is forced to show landscape.. Obviously things will have to be split up/shrunk, because we are working with a 480x96 pixel area. If you are still reading and are interested in helping a poor, stuck soul out, here are some details!
The Ticker "Main" layout screen is located within "framework-res.apk," while the background stuff happens in "services.jar." We do not have the source. I added code to services.jar to get it to rotate (by adding a WindowManger binder to the Ticker Screen). The code for the layout is here:
Code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_gravity="bottom" android:orientation="horizontal" android:id="@id/standbymode_default_vertical" android:background="@null" android:layout_width="fill_parent" android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout android:layout_gravity="top|left|center" android:id="@id/RelativeLayout01" android:layout_width="103.0px" android:layout_height="96.0px">
<ImageView android:layout_gravity="top" android:id="@id/WeatherIcon" android:layout_width="80.0px" android:layout_height="80.0px" android:layout_marginLeft="8.0px" android:layout_marginTop="8.0px" />
<ImageView android:id="@id/IconSel" android:background="@drawable/weather_press" android:visibility="gone" android:layout_width="80.0px" android:layout_height="80.0px" android:layout_marginLeft="8.0px" android:layout_marginTop="8.0px" android:layout_marginBottom="8.0px" />
</RelativeLayout>
<LinearLayout android:orientation="vertical" android:id="@id/LinearLayout02" android:layout_width="0.0dip" android:layout_height="96.0px" android:layout_weight="1.0">
<TextView android:textSize="@dimen/data.text.size" android:textStyle="bold" android:textColor="#ffffffff" android:layout_gravity="top|left|center" android:id="@id/TextView02" android:layout_width="wrap_content" android:layout_height="@dimen/data.layout.height" android:layout_marginTop="@dimen/data.layout.margin.top" android:layout_marginBottom="@dimen/data.layout.margin.bottom" />
<LinearLayout android:gravity="top" android:layout_width="fill_parent" android:layout_height="fill_parent">
<TextView android:textSize="@dimen/time.text.size" android:typeface="normal" android:textColor="@color/clockcolor" android:layout_gravity="top|left|center" android:id="@id/TextView03" android:layout_width="wrap_content" android:layout_height="@dimen/time.layout.height" android:layout_marginBottom="@dimen/time.layout.margin.bottom" />
<TextView android:textSize="@dimen/data.text.size" android:typeface="normal" android:textColor="@color/clockcolor" android:layout_gravity="top|left|center" android:id="@id/TextView04" android:paddingLeft="5.0px" android:layout_width="wrap_content" android:layout_height="@dimen/time.layout.height" android:layout_marginBottom="@dimen/time.layout.margin.bottom" />
</LinearLayout>
</LinearLayout>
<RelativeLayout android:id="@id/RelativeLayout02" android:layout_width="68.0px" android:layout_height="wrap_content">
<ImageButton android:id="@id/HistoryButton" android:background="@null" android:focusable="true" android:layout_width="68.0px" android:layout_height="wrap_content" android:src="@drawable/tt_tickerhistory_buttonup" android:scaleType="fitXY" android:layout_alignParentRight="true" />
</RelativeLayout>
</LinearLayout>
I need to make it so that ^^^ is forced into a landscape view...
Here are some pictures:
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Thanks again to anyone who will take a look! If you need anything, just let me know!!!
Hello. I want to make webview app, but with buttons like in the image that I have created. Back - Refresh - Forvard.
So maybe someone can help, I'm green with it...
Hi there,
So first thing you need to do is grant INTERNET permission to your app by edditing AndroidManifest.xml
For example (I've made all my additions in bold),
Code:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.application.my.webviewtest" >
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
[B]<uses-permission android:name="android.permission.INTERNET" />[/B]
</manifest>
Then you need to edit your View so that you have a WebView widget and some buttons, i'm just showing a back and forward button here, so in my activity_main.xml I have,
Code:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
[B] <LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true">
<WebView
android:layout_width="match_parent"
android:layout_height="400dp"
android:id="@+id/myWebView"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="64dp">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="<"
android:id="@+id/backButton"
android:onClick="OnBackButtonClick"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=">"
android:id="@+id/forwardButton"
android:onClick="OnForwardButtonClick"/>
</LinearLayout>
</LinearLayout>[/B]
</RelativeLayout>
You'll notice I've put it in a vertical linearlayout, and then inside of that a horizontal linearlayout to host the buttons, now for the code in MainActivity.java,
Code:
package com.application.my.webviewtest;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
[B]import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;[/B]
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
[B] WebView webview = (WebView) this.findViewById(R.id.myWebView);
webview.setWebViewClient(new WebViewClient());
webview.getSettings().setJavaScriptEnabled(true);
webview.loadUrl("http://www.google.co.uk");[/B]
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
[B] public void OnBackButtonClick(View view) {
WebView webview = (WebView) this.findViewById(R.id.myWebView);
webview.goBack();
}
public void OnForwardButtonClick(View view) {
WebView webview = (WebView) this.findViewById(R.id.myWebView);
webview.goForward();
}[/B]
}
I've zipped up the app folder of my AndroidStudio project for you
http://npsoftware.s3.amazonaws.com/android/app.zip
I created an main activity with the template "navigation drawer activity" in Android Studio. How can I set the nav drawer for every activity?
activity_main.xml:
Code:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="schemas.android.com/apk/res/android"
xmlns:app="//schemas.android.com/apk/res-auto"
xmlns:tools="//schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>
content_main.xml:
Code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="//schemas.android.com/apk/res/android"
xmlns:app="://schemas.android.com/apk/res-auto"
xmlns:tools="://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".activities.MainActivity"
tools:showIn="@layout/app_bar_main">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello stranger!"
android:id="@+id/textView3" />
</LinearLayout>
nav_header_main.xml
Code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@drawable/side_nav_bar"
android:gravity="bottom"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark"
android:weightSum="1">
<ImageView
android:id="@+id/imageView"
android:layout_width="54dp"
android:layout_height="54dp"
android:maxWidth="10dp"
android:maxHeight="1dp"
android:src="@drawable/library"
android:layout_weight="0.24"
android:paddingLeft="0dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
android:text="Home Library"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="app" />
</LinearLayout>
Main activity:
Code:
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(), NewBookActivity.class);
startActivity(intent);
}
});
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_book) {
Intent intent = new Intent(this, BookListActivity.class);
startActivity(intent);
}
/*else if (id == R.id.nav_gallery) {
}
*/
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
More articles like this, you can visit HUAWEI Developer Forum and Medium.
Forum link: https://forums.developer.huawei.com/forumPortal/en/home
Medium link: https://medium.com/huawei-developers
It is a tradition to exchange business cards with new colleges or partners, but keeping physical business cards is not easy at all. To solve this problem, many apps and mini programs providing the electronic business card function have emerged. You must be wondering how to develop such a function for your app.
Try integrating HUAWEI Nearby Service and use its Nearby Message feature to quickly implement the point-to-point business card exchange function. Check out the function demo below.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
If you are interested in the implementation details, download the source code from GitHub. You can optimize the code based on your app requirements.
Github demo link: https://github.com/HMS-Core/hms-nearby-demo/tree/master/NearbyCardExchange
The development procedure is as follows:
1. Getting Started
If you are already a Huawei developer, skip this step. If you are new to Huawei Mobile Services (HMS), you need to configure app information in AppGallery Connect, enable Nearby Service on the HUAWEI Developers console, and integrate the HMS Core SDK. For details, please refer to the documentation.
2. Adding Permissions
Before using Nearby Message, add the network, Bluetooth, and location permissions. Add the following permissions to the AndroidManifest.xml file of your project:
Code:
<uses-permission android:name="android.permission.INTERNET " />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- The location permission is also required in Android 6.0 or later. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
1. Code Development
2.1 Submitting a Dynamic Permission Application
Ensure that the Bluetooth and location functions are enabled and the device has been connected to the Internet properly. Then submit a dynamic permission application for the location permission.
Code:
@Override
public void onStart() {
super.onStart();
getActivity().getApplication().registerActivityLifecycleCallbacks(this);
checkPermission();
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
for (int i = 0; i < permissions.length; ++i) {
if (grantResults[i] != 0) {
showWarnDialog(Constants.LOCATION_ERROR);
}
}
}
private void checkPermission() {
if (!BluetoothCheckUtil.isBlueEnabled()) {
showWarnDialog(Constants.BLUETOOTH_ERROR);
return;
}
if (!LocationCheckUtil.isLocationEnabled(this.getActivity())) {
showWarnDialog(Constants.LOCATION_SWITCH_ERROR);
return;
}
if (!NetCheckUtil.isNetworkAvailable(this.getActivity())) {
showWarnDialog(Constants.NETWORK_ERROR);
return;
}
String[] deniedPermission = PermissionUtil.getDeniedPermissions(this.getActivity(), new String[] {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
});
if (deniedPermission.length > 0) {
PermissionUtil.requestPermissions(this.getActivity(), deniedPermission, 10);
}
}
2.2 Encapsulating the Business Card Publishing and Subscription APIs
When a subscribed business card message is detected by the onFound method, display it in the business card searching pop-up; when a business card message is no longer discoverable (onLost), delete it from the business card searching pop-up.
Code:
private MessageHandler mMessageHandler = new MessageHandler() {
@Override
public void onFound(Message message) {
CardInfo cardInfo = JsonUtils.json2Object(new String(message.getContent(), Charset.forName("UTF-8")),
CardInfo.class);
if (cardInfo == null) {
return;
}
mSearchCardDialogFragment.addCardInfo(cardInfo);
}
@Override
public void onLost(Message message) {
CardInfo cardInfo = JsonUtils.json2Object(new String(message.getContent(), Charset.forName("UTF-8")),
CardInfo.class);
if (cardInfo == null) {
return;
}
mSearchCardDialogFragment.removeCardInfo(cardInfo);
}
};
private void publish(String namespace, String type, int ttlSeconds, OnCompleteListener<Void> listener) {
Message message = new Message(JsonUtils.object2Json(mCardInfo).getBytes(Charset.forName("UTF-8")), type,
namespace);
Policy policy = new Policy.Builder().setTtlSeconds(ttlSeconds).build();
PutOption option = new PutOption.Builder().setPolicy(policy).build();
Nearby.getMessageEngine(getActivity()).put(message, option).addOnCompleteListener(listener);
}
private void subscribe(String namespace, String type, int ttlSeconds, OnCompleteListener<Void> listener,
GetCallback callback) {
Policy policy = new Policy.Builder().setTtlSeconds(ttlSeconds).build();
MessagePicker picker = new MessagePicker.Builder().includeNamespaceType(namespace, type).build();
GetOption.Builder builder = new GetOption.Builder().setPolicy(policy).setPicker(picker);
if (callback != null) {
builder.setCallback(callback);
}
Nearby.getMessageEngine(getActivity()).get(mMessageHandler, builder.build()).addOnCompleteListener(listener);
}
2.3 Processing the Business Card Exchange Menu
When two users exchange business cards face to face, exchange the business card exchange codes. When the business card message of the remote endpoint is published, subscribe to it.
Code:
private boolean onExchangeItemSelected() {
PinCodeDialogFragment dialogFragment = new PinCodeDialogFragment(passwrod -> {
MyCardFragment.this.publish(passwrod, passwrod, Policy.POLICY_TTL_SECONDS_MAX, result -> {
if (!result.isSuccessful()) {
String str = "Exchange card fail, because publish my card fail. exception: "
+ result.getException().getMessage();
Log.e(TAG, str);
Toast.makeText(getActivity(), str, Toast.LENGTH_LONG).show();
return;
}
MyCardFragment.this.subscribe(passwrod, passwrod, Policy.POLICY_TTL_SECONDS_INFINITE, ret -> {
if (!ret.isSuccessful()) {
MyCardFragment.this.unpublish(passwrod, passwrod, task -> {
String str = "Exchange card fail, because subscribe is fail, exception("
+ ret.getException().getMessage() + ")";
if (!task.isSuccessful()) {
str = str + " and unpublish fail, exception(" + task.getException().getMessage()
+ ")";
}
Log.e(TAG, str);
Toast.makeText(getActivity(), str, Toast.LENGTH_LONG).show();
});
return;
}
mSearchCardDialogFragment.setOnCloseListener(() -> {
MyCardFragment.this.unpublish(passwrod, passwrod, task -> {
if (!task.isSuccessful()) {
Toast.makeText(getActivity(), "Unpublish my card fail, exception: "
+ task.getException().getMessage(), Toast.LENGTH_LONG).show();
}
});
MyCardFragment.this.unsubscribe(task -> {
if (!task.isSuccessful()) {
Toast.makeText(getActivity(), "Unsubscribe fail, exception: "
+ task.getException().getMessage(), Toast.LENGTH_LONG).show();
}
});
});
mSearchCardDialogFragment.show(getParentFragmentManager(), "Search Card");
}, null);
});
});
dialogFragment.show(getParentFragmentManager(), "pin code");
return true;
}
2.4 Adding a Business Card to Favorites
When a user adds a business card to favorites, add the card to the favorites list; when a user removes a business card from favorites, remote the card from the favorites list. In addition, store related data locally.
Code:
@Override
public void onFavorite(CardInfo cardInfo, boolean isFavorite) {
if (isFavorite) {
mFavoriteMap.put(cardInfo.getId(), cardInfo);
} else {
mFavoriteMap.remove(cardInfo.getId());
}
Set<String> set = new HashSet<>(mFavoriteMap.size());
for (CardInfo card : mFavoriteMap.values()) {
set.add(JsonUtils.object2Json(card));
}
SharedPreferences sharedPreferences = getContext().getSharedPreferences("data", Context.MODE_PRIVATE);
sharedPreferences.edit().putStringSet(Constants.MY_FAVORITES_KEY, set).apply();
}
5. Conclusion
This demo uses Nearby Message feature of HUAWEI Nearby Service. What Nearby Message is capable of is more than just developing functions for exchanging business cards face-to-face. Here are some examples:
1. Face-to-face teaming in multiplayer sports games
2. Face-to-face round joining in board games
3. Near-field go-Dutch payment function
4. Music sharing
If you are interested and want to learn more, check our development guide at
https://developer.huawei.com/consumer/en/doc/development/HMS-Guides/nearby-service-introduction
Find more Huawei HMS development guides in the XDA HMS community forums.