{
"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"
}
Hello everyone,
In this article, I will give you some information about the Auth Service offered by Huawei AppGallery Connect to developers and how to use it in cross-platform applications that you will develop with Flutter.
What is Auth Service ?
Many mobile applications require membership systems and authentication methods. Setting up this system from scratch in mobile applications can be difficult and time consuming. Huawei AGC Auth Service enables you to quickly and securely integrate this authentication process into your mobile application. Moreover, Auth Service offers many authentication methods. It can be used in Android Native, IOS Native and cross-platform (Flutter, React-Native, Cordova) projects.
Highly secure, fast and easy to use, Auth Service supports all the following account methods and authentication methods.
Mobile Number (Android, IOS, Web)
Email Address (Android, IOS, Web)
HUAWEI ID (Android)
HUAWEI Game Center account (Android)
WeChat account (Android, IOS, Web)
QQ account (Android, IOS, Web)
Weibo account (Android, IOS)
Apple ID (IOS)
Google account* (Android, IOS)
Google Play Games account* (Android)
Facebook account* (Android, IOS)
Twitter account* (Android, IOS)
Anonymous account (Android, IOS, Web)
Self-owned account (Android, IOS)
Development Steps
Integration
After creating your application on the AGC Console and completing all of the necessary steps, the agconnect-services file should be added to the project first.
The agconnect-services.json configuration file should be added under the android/app directory in the Flutter project.
For IOS, the agconnect-services.plist configuration file should be added under ios/Runner directory in the Flutter project.
Next, the following dependencies for HMS usage need to be added to the build.gradle file under the android directory.
Java:
buildscript {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath 'com.huawei.agconnect:agcp:1.4.2.301'
}
}
allprojects {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
}
Then add the following line of code to the build.gradle file under the android/app directory.
Code:
apply plugin: 'com.huawei.agconnect'
Finally, the Auth Service SDK should be added to the pubspec.yaml file. To do this, open the pubspec.yaml file and add the required dependency as follows.
Code:
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
agconnect_auth: ^1.1.0
agconnect_core: ^1.1.0
And, by clicking “pub get”, the dependencies are added to Android Studio. After all these steps are completed, your app is ready to code.
2. Register with Email
Create a new Dart file named AuthManager that contains all the operations we will do with Auth Service. In this class, the necessary methods for all operations such as sending verification code, registration, login will be written and all operations will be done in this class without any code confusion in the interface class.
When registering with the user’s email address, a verification code must be sent to the entered email address. In this way, it will be determined whether the users are a real person and security measures will be taken. For this, create a method called sendRegisterVerificationCode that takes the email address entered by the user as a parameter and sends a verification code to this email address. By creating a VerifyCodeSettings object within the method, it is specified for what purpose the verification code will be used by making the VerifyCodeAction value “registerLogin”. Finally, with EmailAuthProvider.requestVerifyCode, the verification code is sent to the mail address. Yo can find all of the method on the below.
Java:
void sendRegisterVerificationCode(String email) async{
VerifyCodeSettings settings = VerifyCodeSettings(VerifyCodeAction.registerLogin, sendInterval: 30);
EmailAuthProvider.requestVerifyCode(email, settings)
.then((result){
print("sendRegisterVerificationCode : " + result.validityPeriod);
});
}
After the user receives the verification code, the user is registered with the e-mail address, password, and verification code. Each user must set a special password, and this password must be at least 8 characters long and different from the e-mail address. In addition, lowercase letters, uppercase letters, numbers, spaces or special characters must meet at least two of the requirements. In order to the registration process, a method named registerWithEmail should be created and mail address, verification code and password should be given as parameters. Then create an EmailUser object and set these values. Finally, a new user is created with the AGCAuth.instance.createEmailUser (user) line. You can find registerWithEmail method on the below.
Java:
void registerWithEmail(String email, String verifyCode, String password, BuildContext context) async{
EmailUser user = EmailUser(email, verifyCode, password: password);
AGCAuth.instance.createEmailUser(user)
.then((signInResult) {
print("registerWithEmail : " + signInResult.user.email);
.catchError((error) {
print("Register Error " + error.toString());
_showMyDialog(context, error.toString());
});
}
3. Signin with Email
In order for users to log in to your mobile app after they have registered, a verification code should be sent. To send the verification code while logging in, a method should be created as in the registration, and a verification code should be sent to the e-mail address with this method.
After the verification code is sent, the user can login to the app with their e-mail address, password and verification code. You can test whether the operation is successful by adding .then and .catchError to the login method. You can find all the codes for the sign-in method below.
Java:
void sendSigninVerificationCode(String email) async{
VerifyCodeSettings settings = VerifyCodeSettings(VerifyCodeAction.registerLogin, sendInterval: 30);
EmailAuthProvider.requestVerifyCode(email, settings)
.then((result){
print("sendSigninVerificationCode : " + result.validityPeriod);
});
}
void loginWithEmail(String email, String verifyCode, String password) async{
AGCAuthCredential credential = EmailAuthProvider.credentialWithVerifyCode(email, verifyCode, password: password);
AGCAuth.instance.signIn(credential)
.then((signInResult){
AGCUser user = signInResult.user;
print("loginWithEmail : " + user.displayName);
})
.catchError((error){
print("Login Error " + error.toString());
});
}
4. Reset Password
If the user forgets or wants to change his password, the password reset method provided by Auth Service should be used. Otherwise, the user cannot change his password, and cannot log into his account.
As in every auth method, a verification code is still required when resetting the password. This verification code should be sent to the user’s mail address, similar to the register and sign. Unlike the register and signin operations, the VerifyCodeSettings parameter must be VerifyCodeAction.resetPassword. After sending the verification code to the user’s e-mail address, password reset can be done as follows.
Java:
void sendResetPasswordVerificationCode(String email) async{
VerifyCodeSettings settings = VerifyCodeSettings(VerifyCodeAction.resetPassword, sendInterval: 30);
EmailAuthProvider.requestVerifyCode(email, settings)
.then((result){
print(result.validityPeriod);
});
}
void resetPassword(String email, String newPassword, String verifyCode) async{
AGCAuth.instance.resetPasswordWithEmail(email, newPassword, verifyCode)
.then((value) {
print("Password Reseted");
})
.catchError((error) {
print("Password Reset Error " + error);
});
}
5. Logout
To end the user’s current session, an instance must be created from the AGCAuth object and the signOut() method must be called. You can find this code block on the below.
Java:
void signOut() async{
AGCAuth.instance.signOut().then((value) {
print("SignInSuccess");
}).catchError((error) => print("SignOut Error : " + error));
}
6. User Information
Auth Service provides a lot of data to show the user information of a logged in user. In order to obtain this data, an instance can be created from the AGCAuth object and all the information belonging to the user can be listed with the currentUser method.
Java:
void getCurrentUser() async {
AGCAuth.instance.currentUser.then((value) {
print('current user = ${value?.uid} , ${value?.email} , ${value?.displayName} , ${value?.phone} , ${value?.photoUrl} ');
});
}
The AuthManager class must contain these operations. Thanks to the above methods, you can log in and register with your Email address in your app. You can create an object from the AuthManager class and call the method you need wherever you need it. Now that the AuthManager class is complete, a registration page can be designed and the necessary methods can be called.
7. Create Register Page
I will share an example to give you an idea about design. I designed an animation so that the elements in the page design come with animation at 5 second intervals. In addition, I prepared a design that makes circles around the icon you add periodically to highlight your application’s logo.
I used the avatar_glow library for this. Avatar Glow library allows us to make a simple and stylish design. To add this library, you can add “avatar_glow: ^ 1.1.0” line to pubspec.yaml file and integrate it into your project with “pub get”.
After the library is added, we create a Dart file named DelayedAnimation to run the animations. In this class, we define all the features of animation. You can find all the codes of the class below.
Java:
import 'dart:async';
import 'package:flutter/material.dart';
class DelayedAnimation extends StatefulWidget {
final Widget child;
final int delay;
DelayedAnimation({@required this.child, this.delay});
@override
_DelayedAnimationState createState() => _DelayedAnimationState();
}
class _DelayedAnimationState extends State<DelayedAnimation>
with TickerProviderStateMixin {
AnimationController _controller;
Animation<Offset> _animOffset;
@override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 800));
final curve =
CurvedAnimation(curve: Curves.decelerate, parent: _controller);
_animOffset =
Tween<Offset>(begin: const Offset(0.0, 0.35), end: Offset.zero)
.animate(curve);
if (widget.delay == null) {
_controller.forward();
} else {
Timer(Duration(milliseconds: widget.delay), () {
_controller.forward();
});
}
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
@override
Widget build(BuildContext context) {
return FadeTransition(
child: SlideTransition(
position: _animOffset,
child: widget.child,
),
opacity: _controller,
);
}
}
Then we can create a Dart file called RegisterPage and continue coding.
In this class, we first set a fixed delay time. I set it to 500 ms. Then I increased it by 500ms for each element and made it load one after the other.
Then TextEditingController objects should be created to get values such as email, password, verify code written into TextFormField.
Finally, when clicked the send verification code button, I set a visibility value as bool to change the name of the button and the visibility of the field where a new verification code will be entered.
Java:
final int delayedAmount = 500;
AnimationController _controller;
bool _visible = false;
String buttonText = "Send Verify Code";
TextEditingController emailController = new TextEditingController();
TextEditingController passwordController = new TextEditingController();
TextEditingController verifyCodeController = new TextEditingController();
Now, AnimationController values must be set in initState method.
Java:
@override
void initState() {
_controller = AnimationController(
vsync: this,
duration: Duration(
milliseconds: 200,
),
lowerBound: 0.0,
upperBound: 0.1,
)..addListener(() {
setState(() {});
});
super.initState();
}
Then a method should be created for the verification code send button and the save button, and these methods should be called in the Widget build method where necessary. In both methods, first of all, the visibility values and texts should be changed and the related methods should be called by creating an object from the AuthManager class.
Java:
void _toggleVerifyCode() {
setState(() {
_visible = true;
buttonText = "Send Again";
final AuthManager authManager = new AuthManager();
authManager.sendRegisterVerificationCode(emailController.text);
});
}
void _toggleRegister() {
setState(() {
_visible = true;
buttonText = "Send Again";
final AuthManager authManager = new AuthManager();
authManager.registerWithEmail(emailController.text, verifyCodeController.text, passwordController.text, this.context);
});
}
Finally, in the Widget build method, the design of each element should be prepared separately and returned at the end. If all the codes are written under return, the code will look too complex and debugging or modification will be difficult. As seen on the below, I prepared an Avatar Glow object at the top. Then, create two TextFormFields for the user to enter their mail address and password. Under these two TextFormFields, there is a button for sending the verification code. When this button is clicked, a verification code is sent to the mail address, and a new button design is created for entering this verification code and a new TextFormField and register operations. Yo can find screenshots and all of the codes on the below.
Java:
@override
Widget build(BuildContext context) {
final color = Color(0xFFF4EADE);
_scale = 1 - _controller.value;
final logo = AvatarGlow(
endRadius: 90,
duration: Duration(seconds: 2),
glowColor: Color(0xFF2F496E),
repeat: true,
repeatPauseDuration: Duration(seconds: 2),
startDelay: Duration(seconds: 1),
child: Material(
elevation: 8.0,
shape: CircleBorder(),
child: CircleAvatar(
backgroundColor: Color(0xFFF4EADE),
backgroundImage: AssetImage('assets/huawei_logo.png'),
radius: 50.0,
)
),
);
final title = DelayedAnimation(
child: Text(
"Register",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 35.0,
color: Color(0xFF2F496E)),
),
delay: delayedAmount + 500,
);
final email = DelayedAnimation(
delay: delayedAmount + 500,
child: TextFormField(
controller: emailController,
keyboardType: TextInputType.emailAddress,
autofocus: false,
decoration: InputDecoration(
hintText: '* Email',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(100.0)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(100.0),
borderSide: BorderSide(
color: Color(0xFF2F496E),
),
),
),
),
);
final password = DelayedAnimation(
delay: delayedAmount + 1000,
child: TextFormField(
controller: passwordController,
autofocus: false,
obscureText: true,
decoration: InputDecoration(
hintText: '* Password',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(100.0)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(100.0),
borderSide: BorderSide(
color: Color(0xFF2F496E),
),
),
),
),
);
final sendVerifyCodeButton = RaisedButton(
color: Color(0xFF2F496E),
highlightColor: Color(0xFF2F496E),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100.0),
),
onPressed: _toggleVerifyCode,
child: Text(
buttonText,
style: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.normal,
color: color,
),
),
);
final verifyCode = DelayedAnimation(
delay: 500,
child: TextFormField(
controller: verifyCodeController,
keyboardType: TextInputType.emailAddress,
autofocus: false,
decoration: InputDecoration(
hintText: '* Verify Code',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(100.0)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(100.0),
borderSide: BorderSide(
color: Color(0xFF2F496E),
),
),
),
),
);
final registerButton = RaisedButton(
color: Color(0xFF2F496E),
highlightColor: Color(0xFF2F496E),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100.0),
),
onPressed: _toggleRegister,
child: Text(
'Register',
style: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.normal,
color: color,
),
),
);
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Color(0xFFF4EADE),
body: Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
new Container(
margin: const EdgeInsets.all(20.0),
child: new Container()
),
title,
logo,
SizedBox(
height: 50,
width: 300,
child: email,
),
SizedBox(height: 15.0),
SizedBox(
height: 50,
width: 300,
child: password,
),
SizedBox(height: 15.0),
SizedBox(
height: 40,
width: 300,
child: DelayedAnimation(
delay: delayedAmount + 1500,
child: sendVerifyCodeButton
),
),
SizedBox(height: 15.0),
SizedBox(
height: 50,
width: 300,
child: Visibility(
maintainSize: true,
maintainAnimation: true,
maintainState: true,
visible: _visible,
child: DelayedAnimation(
delay: delayedAmount + 1500,
child: verifyCode
),
)
),
SizedBox(height: 15.0),
SizedBox(
height: 50,
width: 300,
child: Visibility(
maintainSize: true,
maintainAnimation: true,
maintainState: true,
visible: _visible,
child: DelayedAnimation(
delay: delayedAmount + 1500,
child: registerButton
),
)
),
SizedBox(height: 50.0,),
],
),
),
),
),
);
}
8. Create Login Page
We coded the all of requirements for login in the AuthManager class as above. Using the same design on the Register page and changing the button’s onPressed method, the Login page can be created easily. Since all codes are the same, I will not share the codes for this class again. As I mentioned, this is just a design example, you can change your login and registration pages to your application needs.
More details perhaps?
hello team #XDA, i have entered Google pixel 5 contest of yours
Nice
good
It s everything on one place for learning about manufactured,about java and the programs and is realy helpful,thank you for your sharing knowledge with us,and i am in the contest for the pixel 5 sure it will be awesome will learning to have better phone on focusing knowledge in programs,thanks for all
Helpful
Kill For It
XDARoni said:
Hello everyone,
In this article, I will give you some information about the Auth Service offered by Huawei AppGallery Connect to developers and how to use it in cross-platform applications that you will develop with Flutter.
What is Auth Service ?
Many mobile applications require membership systems and authentication methods. Setting up this system from scratch in mobile applications can be difficult and time consuming. Huawei AGC Auth Service enables you to quickly and securely integrate this authentication process into your mobile application. Moreover, Auth Service offers many authentication methods. It can be used in Android Native, IOS Native and cross-platform (Flutter, React-Native, Cordova) projects.
Highly secure, fast and easy to use, Auth Service supports all the following account methods and authentication methods.
Mobile Number (Android, IOS, Web)
Email Address (Android, IOS, Web)
HUAWEI ID (Android)
HUAWEI Game Center account (Android)
WeChat account (Android, IOS, Web)
QQ account (Android, IOS, Web)
Weibo account (Android, IOS)
Apple ID (IOS)
Google account* (Android, IOS)
Google Play Games account* (Android)
Facebook account* (Android, IOS)
Twitter account* (Android, IOS)
Anonymous account (Android, IOS, Web)
Self-owned account (Android, IOS)
Development Steps
Integration
After creating your application on the AGC Console and completing all of the necessary steps, the agconnect-services file should be added to the project first.
The agconnect-services.json configuration file should be added under the android/app directory in the Flutter project.
For IOS, the agconnect-services.plist configuration file should be added under ios/Runner directory in the Flutter project.
Next, the following dependencies for HMS usage need to be added to the build.gradle file under the android directory.
Java:
buildscript {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath 'com.huawei.agconnect:agcp:1.4.2.301'
}
}
allprojects {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
}
Then add the following line of code to the build.gradle file under the android/app directory.
Code:
apply plugin: 'com.huawei.agconnect'
Finally, the Auth Service SDK should be added to the pubspec.yaml file. To do this, open the pubspec.yaml file and add the required dependency as follows.
Code:
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
agconnect_auth: ^1.1.0
agconnect_core: ^1.1.0
And, by clicking “pub get”, the dependencies are added to Android Studio. After all these steps are completed, your app is ready to code.
2. Register with Email
Create a new Dart file named AuthManager that contains all the operations we will do with Auth Service. In this class, the necessary methods for all operations such as sending verification code, registration, login will be written and all operations will be done in this class without any code confusion in the interface class.
When registering with the user’s email address, a verification code must be sent to the entered email address. In this way, it will be determined whether the users are a real person and security measures will be taken. For this, create a method called sendRegisterVerificationCode that takes the email address entered by the user as a parameter and sends a verification code to this email address. By creating a VerifyCodeSettings object within the method, it is specified for what purpose the verification code will be used by making the VerifyCodeAction value “registerLogin”. Finally, with EmailAuthProvider.requestVerifyCode, the verification code is sent to the mail address. Yo can find all of the method on the below.
Java:
void sendRegisterVerificationCode(String email) async{
VerifyCodeSettings settings = VerifyCodeSettings(VerifyCodeAction.registerLogin, sendInterval: 30);
EmailAuthProvider.requestVerifyCode(email, settings)
.then((result){
print("sendRegisterVerificationCode : " + result.validityPeriod);
});
}
After the user receives the verification code, the user is registered with the e-mail address, password, and verification code. Each user must set a special password, and this password must be at least 8 characters long and different from the e-mail address. In addition, lowercase letters, uppercase letters, numbers, spaces or special characters must meet at least two of the requirements. In order to the registration process, a method named registerWithEmail should be created and mail address, verification code and password should be given as parameters. Then create an EmailUser object and set these values. Finally, a new user is created with the AGCAuth.instance.createEmailUser (user) line. You can find registerWithEmail method on the below.
Java:
void registerWithEmail(String email, String verifyCode, String password, BuildContext context) async{
EmailUser user = EmailUser(email, verifyCode, password: password);
AGCAuth.instance.createEmailUser(user)
.then((signInResult) {
print("registerWithEmail : " + signInResult.user.email);
.catchError((error) {
print("Register Error " + error.toString());
_showMyDialog(context, error.toString());
});
}
3. Signin with Email
In order for users to log in to your mobile app after they have registered, a verification code should be sent. To send the verification code while logging in, a method should be created as in the registration, and a verification code should be sent to the e-mail address with this method.
After the verification code is sent, the user can login to the app with their e-mail address, password and verification code. You can test whether the operation is successful by adding .then and .catchError to the login method. You can find all the codes for the sign-in method below.
Java:
void sendSigninVerificationCode(String email) async{
VerifyCodeSettings settings = VerifyCodeSettings(VerifyCodeAction.registerLogin, sendInterval: 30);
EmailAuthProvider.requestVerifyCode(email, settings)
.then((result){
print("sendSigninVerificationCode : " + result.validityPeriod);
});
}
void loginWithEmail(String email, String verifyCode, String password) async{
AGCAuthCredential credential = EmailAuthProvider.credentialWithVerifyCode(email, verifyCode, password: password);
AGCAuth.instance.signIn(credential)
.then((signInResult){
AGCUser user = signInResult.user;
print("loginWithEmail : " + user.displayName);
})
.catchError((error){
print("Login Error " + error.toString());
});
}
4. Reset Password
If the user forgets or wants to change his password, the password reset method provided by Auth Service should be used. Otherwise, the user cannot change his password, and cannot log into his account.
As in every auth method, a verification code is still required when resetting the password. This verification code should be sent to the user’s mail address, similar to the register and sign. Unlike the register and signin operations, the VerifyCodeSettings parameter must be VerifyCodeAction.resetPassword. After sending the verification code to the user’s e-mail address, password reset can be done as follows.
Java:
void sendResetPasswordVerificationCode(String email) async{
VerifyCodeSettings settings = VerifyCodeSettings(VerifyCodeAction.resetPassword, sendInterval: 30);
EmailAuthProvider.requestVerifyCode(email, settings)
.then((result){
print(result.validityPeriod);
});
}
void resetPassword(String email, String newPassword, String verifyCode) async{
AGCAuth.instance.resetPasswordWithEmail(email, newPassword, verifyCode)
.then((value) {
print("Password Reseted");
})
.catchError((error) {
print("Password Reset Error " + error);
});
}
5. Logout
To end the user’s current session, an instance must be created from the AGCAuth object and the signOut() method must be called. You can find this code block on the below.
Java:
void signOut() async{
AGCAuth.instance.signOut().then((value) {
print("SignInSuccess");
}).catchError((error) => print("SignOut Error : " + error));
}
6. User Information
Auth Service provides a lot of data to show the user information of a logged in user. In order to obtain this data, an instance can be created from the AGCAuth object and all the information belonging to the user can be listed with the currentUser method.
Java:
void getCurrentUser() async {
AGCAuth.instance.currentUser.then((value) {
print('current user = ${value?.uid} , ${value?.email} , ${value?.displayName} , ${value?.phone} , ${value?.photoUrl} ');
});
}
The AuthManager class must contain these operations. Thanks to the above methods, you can log in and register with your Email address in your app. You can create an object from the AuthManager class and call the method you need wherever you need it. Now that the AuthManager class is complete, a registration page can be designed and the necessary methods can be called.
7. Create Register Page
I will share an example to give you an idea about design. I designed an animation so that the elements in the page design come with animation at 5 second intervals. In addition, I prepared a design that makes circles around the icon you add periodically to highlight your application’s logo.
I used the avatar_glow library for this. Avatar Glow library allows us to make a simple and stylish design. To add this library, you can add “avatar_glow: ^ 1.1.0” line to pubspec.yaml file and integrate it into your project with “pub get”.
After the library is added, we create a Dart file named DelayedAnimation to run the animations. In this class, we define all the features of animation. You can find all the codes of the class below.
Java:
import 'dart:async';
import 'package:flutter/material.dart';
class DelayedAnimation extends StatefulWidget {
final Widget child;
final int delay;
DelayedAnimation({@required this.child, this.delay});
@override
_DelayedAnimationState createState() => _DelayedAnimationState();
}
class _DelayedAnimationState extends State<DelayedAnimation>
with TickerProviderStateMixin {
AnimationController _controller;
Animation<Offset> _animOffset;
@override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 800));
final curve =
CurvedAnimation(curve: Curves.decelerate, parent: _controller);
_animOffset =
Tween<Offset>(begin: const Offset(0.0, 0.35), end: Offset.zero)
.animate(curve);
if (widget.delay == null) {
_controller.forward();
} else {
Timer(Duration(milliseconds: widget.delay), () {
_controller.forward();
});
}
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
@override
Widget build(BuildContext context) {
return FadeTransition(
child: SlideTransition(
position: _animOffset,
child: widget.child,
),
opacity: _controller,
);
}
}
Then we can create a Dart file called RegisterPage and continue coding.
In this class, we first set a fixed delay time. I set it to 500 ms. Then I increased it by 500ms for each element and made it load one after the other.
Then TextEditingController objects should be created to get values such as email, password, verify code written into TextFormField.
Finally, when clicked the send verification code button, I set a visibility value as bool to change the name of the button and the visibility of the field where a new verification code will be entered.
Java:
final int delayedAmount = 500;
AnimationController _controller;
bool _visible = false;
String buttonText = "Send Verify Code";
TextEditingController emailController = new TextEditingController();
TextEditingController passwordController = new TextEditingController();
TextEditingController verifyCodeController = new TextEditingController();
Now, AnimationController values must be set in initState method.
Java:
@override
void initState() {
_controller = AnimationController(
vsync: this,
duration: Duration(
milliseconds: 200,
),
lowerBound: 0.0,
upperBound: 0.1,
)..addListener(() {
setState(() {});
});
super.initState();
}
Then a method should be created for the verification code send button and the save button, and these methods should be called in the Widget build method where necessary. In both methods, first of all, the visibility values and texts should be changed and the related methods should be called by creating an object from the AuthManager class.
Java:
void _toggleVerifyCode() {
setState(() {
_visible = true;
buttonText = "Send Again";
final AuthManager authManager = new AuthManager();
authManager.sendRegisterVerificationCode(emailController.text);
});
}
void _toggleRegister() {
setState(() {
_visible = true;
buttonText = "Send Again";
final AuthManager authManager = new AuthManager();
authManager.registerWithEmail(emailController.text, verifyCodeController.text, passwordController.text, this.context);
});
}
Finally, in the Widget build method, the design of each element should be prepared separately and returned at the end. If all the codes are written under return, the code will look too complex and debugging or modification will be difficult. As seen on the below, I prepared an Avatar Glow object at the top. Then, create two TextFormFields for the user to enter their mail address and password. Under these two TextFormFields, there is a button for sending the verification code. When this button is clicked, a verification code is sent to the mail address, and a new button design is created for entering this verification code and a new TextFormField and register operations. Yo can find screenshots and all of the codes on the below.
Java:
@override
Widget build(BuildContext context) {
final color = Color(0xFFF4EADE);
_scale = 1 - _controller.value;
final logo = AvatarGlow(
endRadius: 90,
duration: Duration(seconds: 2),
glowColor: Color(0xFF2F496E),
repeat: true,
repeatPauseDuration: Duration(seconds: 2),
startDelay: Duration(seconds: 1),
child: Material(
elevation: 8.0,
shape: CircleBorder(),
child: CircleAvatar(
backgroundColor: Color(0xFFF4EADE),
backgroundImage: AssetImage('assets/huawei_logo.png'),
radius: 50.0,
)
),
);
final title = DelayedAnimation(
child: Text(
"Register",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 35.0,
color: Color(0xFF2F496E)),
),
delay: delayedAmount + 500,
);
final email = DelayedAnimation(
delay: delayedAmount + 500,
child: TextFormField(
controller: emailController,
keyboardType: TextInputType.emailAddress,
autofocus: false,
decoration: InputDecoration(
hintText: '* Email',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(100.0)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(100.0),
borderSide: BorderSide(
color: Color(0xFF2F496E),
),
),
),
),
);
final password = DelayedAnimation(
delay: delayedAmount + 1000,
child: TextFormField(
controller: passwordController,
autofocus: false,
obscureText: true,
decoration: InputDecoration(
hintText: '* Password',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(100.0)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(100.0),
borderSide: BorderSide(
color: Color(0xFF2F496E),
),
),
),
),
);
final sendVerifyCodeButton = RaisedButton(
color: Color(0xFF2F496E),
highlightColor: Color(0xFF2F496E),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100.0),
),
onPressed: _toggleVerifyCode,
child: Text(
buttonText,
style: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.normal,
color: color,
),
),
);
final verifyCode = DelayedAnimation(
delay: 500,
child: TextFormField(
controller: verifyCodeController,
keyboardType: TextInputType.emailAddress,
autofocus: false,
decoration: InputDecoration(
hintText: '* Verify Code',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(100.0)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(100.0),
borderSide: BorderSide(
color: Color(0xFF2F496E),
),
),
),
),
);
final registerButton = RaisedButton(
color: Color(0xFF2F496E),
highlightColor: Color(0xFF2F496E),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100.0),
),
onPressed: _toggleRegister,
child: Text(
'Register',
style: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.normal,
color: color,
),
),
);
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Color(0xFFF4EADE),
body: Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
new Container(
margin: const EdgeInsets.all(20.0),
child: new Container()
),
title,
logo,
SizedBox(
height: 50,
width: 300,
child: email,
),
SizedBox(height: 15.0),
SizedBox(
height: 50,
width: 300,
child: password,
),
SizedBox(height: 15.0),
SizedBox(
height: 40,
width: 300,
child: DelayedAnimation(
delay: delayedAmount + 1500,
child: sendVerifyCodeButton
),
),
SizedBox(height: 15.0),
SizedBox(
height: 50,
width: 300,
child: Visibility(
maintainSize: true,
maintainAnimation: true,
maintainState: true,
visible: _visible,
child: DelayedAnimation(
delay: delayedAmount + 1500,
child: verifyCode
),
)
),
SizedBox(height: 15.0),
SizedBox(
height: 50,
width: 300,
child: Visibility(
maintainSize: true,
maintainAnimation: true,
maintainState: true,
visible: _visible,
child: DelayedAnimation(
delay: delayedAmount + 1500,
child: registerButton
),
)
),
SizedBox(height: 50.0,),
],
),
),
),
),
);
}
8. Create Login Page
We coded the all of requirements for login in the AuthManager class as above. Using the same design on the Register page and changing the button’s onPressed method, the Login page can be created easily. Since all codes are the same, I will not share the codes for this class again. As I mentioned, this is just a design example, you can change your login and registration pages to your application needs.
Click to expand...
Click to collapse
I like flutter ui ux
Useful and easy.
Related
For homework, we're required to write code for a cash register. Basically what it does is it prints out a menu and asks the user for input. At the end it prints out the order along with the total.
The part I am having trouble with is how do I make something like this:
Code:
Hamburger Hamburger Hamburger
display as this:
Code:
(3) Hamburger
We're told to think in terms of parallel arrays, but seeing as I missed that class, I am a bit lost.
If wanted, I can put up what code I have.
Thanks in advance.
can you post all your code?
Here is what I have.
I haven't written anything in my code that would relate to the problem I am having because I do not know where to start.
Code:
import java.util.Scanner;
import java.util.ArrayList;
public class CashRegister{
public static void main(String[]args){
Scanner scan=new Scanner(System.in);
ArrayList<String> list=new ArrayList<String>();
Register reg=new Register();
int b;
do{
String [] item = new String[11];
item [0]="Hot Dog";
item [1]="Hamburger";
item [2]="Soda";
item [3]="Chips";
item [4]="Ice Cream";
item [5]="Shave Ice";
item [6]="Cookie";
item [7]="Plate Lunch";
item [8]="French Fries";
item [9]="Shake";
item [10]="Order Complete";
for (int a=0;a<item.length;a++){
System.out.println((a+1)+". "+item[a]);}
b=scan.nextInt();
if (b==1){
list.add(item[0]);
reg.add(2.50);}
if (b==2){
list.add(item[1]);
reg.add(3.00);}
if (b==3){
list.add(item[2]);
reg.add(1.25);}
if (b==4){
list.add(item[3]);
reg.add(1.50);}
if (b==5){
list.add(item[4]);
reg.add(2.00);}
if (b==6){
list.add(item[5]);
reg.add(2.00);}
if (b==7){
list.add(item[6]);
reg.add(1.00);}
if (b==8){
list.add(item[7]);
reg.add(5.00);}
if (b==9){
list.add(item[8]);
reg.add(2.50);}
if (b==10){
list.add(item[9]);
reg.add(3.00);}
}
while (b != 11);
System.out.println("");
System.out.println("Your order contains: ");
System.out.println(list);
System.out.print("Your order costs: $");
double f=reg.getTotal();
System.out.format("%.2f %n",f);
}}
class Register{
double total=0;
public void add (double b){
total=total+b;}
public double getTotal(){
return total;}
}
I looked into your code and I can see what you want to do. I came up with a way to do it, however, I don't think it will be an efficient code (I'm not really familiar with Java).
I'm sure someone with more knowledge with Java could help you with this.
If you don't mind, could you post what you came up with or maybe point me in the right direction? Thanks
Sent from 234 Elm Street
We're told to think in terms of parallel arrays, but seeing as I missed that class, I am a bit lost.
If wanted, I can put up what code I have.
Thanks in advance.
Click to expand...
Click to collapse
Woops! I haven't read that, here is the almost much more cleaner solution.
There are several things that could be done (checking for valid input for example, ...) but i think thats to much for now.
Code:
import java.util.ArrayList;
import java.util.Scanner;
public class CashRegister {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
ArrayList<String> order = new ArrayList<String>();
Register reg = new Register();
// init & declare the array outside the loop
String[] menu = new String[] { "Hot Dog", "Hamburger", "Soda", "Chips",
"Ice Cream", "Shave Ice", "Cookie", "Plate Lunch",
"French Fries", "Shake" };
double[] prices = new double[] { 2.50, 3.00, 1.25, 1.50, 2.00, 2.00,
1.00, 5.00, 2.50, 3.00 };
// every order contains a amount int
int[] amountOf = new int[10];
for (int a = 0; a < menu.length; a++) {
System.out.println((a) + ". " + menu[a]);
}
System.out.println("10. " + "Order Complete");
System.out.print("Please choose from the menu:");
int input;
do {
input = scan.nextInt();
if (input >= 0 && input <= 10) {
reg.add(prices[input]);
amountOf[input]++;
}
}
while (input != 11);
System.out.println("");
System.out.println("Your order contains: ");
// System.out.println(list);
// calculate the amount of items from the order
for (int singleItem = 0; singleItem < menu.length; singleItem++) {
for (int menuIndex = 0; menuIndex < order.size(); menuIndex++) {
if (order.get(menuIndex).equals(menu[singleItem])) {
amountOf[singleItem]++;
}
}
}
// print the receipt
for (int i = 0; i < amountOf.length; i++) {
if (amountOf[i] > 0) {
System.out.println("(" + amountOf[i] + ") " + menu[i]);
}
}
System.out.print("Your order costs: $");
double f = reg.getTotal();
System.out.format("%.2f %n", f);
}
}
class Register {
private double total = 0;
public void add(double b) {
total = total + b;
}
public double getTotal() {
return total;
}
}
Thanks for your help. Now I can rest until the next assignment...which is tonight.
slow_DC4 said:
Thanks for your help. Now I can rest until the next assignment...which is tonight.
Click to expand...
Click to collapse
You know where to ask
Hi, sadly, it's me again seeking for some help.
This is what we are supposed to do
Code:
In this assignment you will use the techniques you used in lab to create an interactive vending machine. You must use Arraylists to store the information about the items for sale in the machine. Use the class you created in Assignment 5 in your ArrayLists.
Only the first item in a slot can be sold.
Hint:
Declaring and ArrayList of ArrayLists
Where Type is your class:
ArrayList<ArrayList<Type>> array;
You must also add each ArrayList to the ArrayList
array.add(new ArrayList<Type>());
End Hint
All Methods listed should be public:
Items will follow the restrictions delineated in Assignment 5. (You should leverage the abilities built into that class)
You will create a VendingMachine class that has at least the following methods:
VendingMachine(int numSlots, int maxItems)
This constructor will set up the object so that numSlots is the number of slots the machine has. MaxItems will be the maximum number of items that can be placed in each slot.
void menu()
This method will print a list of the items available, their price and the slot it is in. Only the first item in a slot will be printed. If a slot is Empty “Empty” should be printed with $0.00 for the price. Will also print out the current amount held in the machine.
boolean load(int slotNum, String name, double price, int quantity)
This method will load items into the machine. slotNum will be the slot that the items will be placed in, name will be the name of the item in the machine and price the price. Quantity is the number of this item that should be added. If the quantity exceeds the current capacity of the slot it should add nothing to the slot and return false. If the loading is successful return true.
int capacity(int slotNum)
returns the number of spaces empty in the slot specified.
void insertMoney( double money)
Will increase the amount of money in the machine by the amount of money (will not do anything if money is negative)
double returnMoney()
Will set amount of money in the machine to 0 and return the amount that was in the machine.
boolean select(int slotNumber)
Attempts to purchase the item in the slotnumber selected it returns true if the sale was successful and false if it was not. For a successful sale the amount held in the machine must be greater than the selected item. There must also be a valid item to be sold (the slot is not empty). If the item is sold the amount in the machine should be decreased by the price of the item. The first items in the slot should be removed.
This is what I have:
Code:
import java.util.ArrayList;
class itemVend{
public String item;
public double price;
final double maxPrice=99.99;
public itemVend(String item, double price){
this.item=item;
this.price=price;
}
public String getItem(){
if (item.length()>20){
item=item.substring(0,20);
}
System.out.println(item);
return item;
}
public double getPrice(){
if (price>=100.00){
price=99.99;
}
String priceNormal=String.format("%.2f",price);
System.out.format("$%5s",priceNormal);
double nPrice=Double.valueOf(priceNormal);
return nPrice;
}
}
class VendingMachine{
int numSlots;
int maxItems;
int slotNum;
String name;
double price;
int quantity;
double total;
double money;
int [] NumSlot=new int[numSlots];
int [] SlotAdd=new int [maxItems];
ArrayList<ArrayList<VendingMachine>> VendM;
public VendingMachine(int numSlots, int maxItems){
this.numSlots=numSlots;
this.maxItems=maxItems;
}
/*
public void menu(){
for (int x=0;x<numSlots;x++){
System.out.print(NumSlot[x]+","+name+","+price);
}
}
*/
public boolean load (int slotNum, String name, double price,int quantity){
if (quantity<=maxItems){
this.slotNum=slotNum;
this.name=name;
this.price=price;
itemVend IV=new itemVend(name,price);
this.quantity=quantity;
return true;
}
else {
return false;
}
}
public int capacity (int slotNum){
int emptySpace=maxItems-quantity;
return emptySpace;
}
public void insertMoney (double money){
total=total+money;
}
public boolean select(int slotNum){
if ((money>price)){
total=total-price;
return true;
}
else {
return false;
}
}
}
It's not quite done yet, and I'm sure that I have a lot of errors, because I am getting a little frustrated. The parts that I am having the most difficulty with is the VendingMachine constructor and the printing of the menu. Also I don't understand how the hint applies.
I think I may have figured out the menu problem:
Code:
public void menu(){
for (int x=0;x<VendNumber.size();x++){
System.out.println("Slot number: "+VendNumber.get(x)+", Item Name: "+VendItemName.get(x)+", Item Price: $"+ItemPrice.get(x));
}
}
Assignment 5 refers to the itemVend class.
Thanks in advance.
I'll take a look at this at the weekend, maybe tomorrow.
I have a textview that shows your amount of money and i would like the ui to update every second to visually show how much money you have in real time. Would i be able to accomplish this with a timer?, and if so what would it look like.
Hello,
You should do inside your class, outside of any method:
Code:
TextView tv;
String calculatedString;
MyAsyncTask mAsync = null;
Timer timer = null;
TimerTask task = null;
private class MyAsyncTask extends AsyncTask<String, Void, String> {
public MyAsyncTask(){
}
@Override
protected String doInBackground(String... params) {
//Background operation in a separate thread
//Write here your code to run in the background thread
//calculate here whatever you like
calculatedString = ....;
return null;
}
@Override
protected void onPostExecute(String result) {
//Called on Main UI Thread. Executed after the Background operation, allows you to have access to the UI
tv.setText(calculatedString);
}
@Override
protected void onPreExecute() {
//Called on Main UI Thread. Executed before the Background operation, allows you to have access to the UI
}
}
inside the onCreate after super and setContentView:
Code:
tv = (TextView) findViewById(R.id.tv); //your tv id here
final Handler handler = new Handler();
timer = new Timer();
task = new TimerTask() {
@Override
public void run() {
handler.post(new Runnable() {
public void run() {
MyAsyncTask mAsync = new MyAsyncTask();
mAsync.execute();
}
});
}
};
timer.schedule(task, 0, 1000); //Every 1 second
If you still need help, feel free to ask
I have attached 2 screenshots showing the errors i was given after inputting. Any idea how to fix this?
mmdeveloper10 said:
Hello,
You should do inside your class, outside of any method:
Code:
TextView tv;
String calculatedString;
MyAsyncTask mAsync = null;
Timer timer = null;
TimerTask task = null;
private class MyAsyncTask extends AsyncTask<String, Void, String> {
public MyAsyncTask(){
}
@Override
protected String doInBackground(String... params) {
//Background operation in a separate thread
//Write here your code to run in the background thread
//calculate here whatever you like
calculatedString = ....;
return null;
}
@Override
protected void onPostExecute(String result) {
//Called on Main UI Thread. Executed after the Background operation, allows you to have access to the UI
tv.setText(calculatedString);
}
@Override
protected void onPreExecute() {
//Called on Main UI Thread. Executed before the Background operation, allows you to have access to the UI
}
}
inside the onCreate after super and setContentView:
Code:
tv = (TextView) findViewById(R.id.tv); //your tv id here
final Handler handler = new Handler();
timer = new Timer();
task = new TimerTask() {
@Override
public void run() {
handler.post(new Runnable() {
public void run() {
MyAsyncTask mAsync = new MyAsyncTask();
mAsync.execute();
}
});
}
};
timer.schedule(task, 0, 1000); //Every 1 second
If you still need help, feel free to ask
Click to expand...
Click to collapse
Hello,
For the first image:
You have to import the AsyncTask.
add this
Code:
import android.os.AsyncTask;
with the other imports in your java file.
For your second image:
You haven't wrote the line
Code:
setContentView(R.layout.activity_main);
under your super.onCreate(savedInstanceState); and then the code I said above (I said that on my post )
inside onCreate, where activity_main is your xml layout. And you should have inside that layout, a TextView with an id "tv" (or whatever you like)
and then:
Code:
tv = (TextView) findViewById(R.id.tv); //your tv id here
R.id.tv must much the id you have in your layout. Replace it with the actual id of your TextView. If your id is "tv", write R.id.tv, if it is "mytv" write R.id.mytv. ( I said that on my post also)
Can you show your layout file? (XML - your activity_main.xml). You said that you have a TextView Where is your TextView?
Ok I fixed the problems stated and now only have these two errors remaining
mmdeveloper10 said:
Hello,
For the first image:
You have to import the AsyncTask.
add this
Code:
import android.os.AsyncTask;
with the other imports in your java file.
For your second image:
You haven't wrote the line
Code:
setContentView(R.layout.activity_main);
under your super.onCreate(savedInstanceState); and then the code I said above (I said that on my post )
inside onCreate, where activity_main is your xml layout. And you should have inside that layout, a TextView with an id "tv" (or whatever you like)
and then:
Code:
tv = (TextView) findViewById(R.id.tv); //your tv id here
R.id.tv must much the id you have in your layout. Replace it with the actual id of your TextView. If your id is "tv", write R.id.tv, if it is "mytv" write R.id.mytv. ( I said that on my post also)
Can you show your layout file? (XML - your activity_main.xml). You said that you have a TextView Where is your TextView?
Click to expand...
Click to collapse
Have you imported this?
Code:
import java.util.logging.Handler;
If so, change it to
Code:
import android.os.Handler;
Im not at the computer but I think that should solve my issue I will keep you updated
Sent from my HTC6525LVW using XDA Free mobile app
Hey thanks so much its working perfectly now :good:
I am trying to use m_BTArrayAdapter.getCount()
However this function returns 0 regardless of what is in the spinner popup.
I found some doco on this function: http://developer.android.com/reference/android/widget/ArrayAdapter.html#getCount%28%29
"public int getCount ()"
That is - no description. So what does that mean? In android Studio this function is redundant?
There are no other functions that I can see that tell you how many items there are in an ArrayAdapter or in the spinner control itself.
Surely I don't have to resort to a counter in my BT listener function to keep count of how many items are added to the adapter????
Code:
void setupBTListener()
{
m_BTArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item);
final Spinner spinnerBluetooth = (Spinner)findViewById(id.spinner_bluetooth);
spinnerBluetooth.setAdapter(m_BTArrayAdapter);
Can anyone explain to me why m_BTArrayAdapter.getCount() returns non zero inside my listener function but zero in the code below?
Code:
m_BTArrayAdapter.clear();
if (m_BTAdapter.isDiscovering())
m_BTAdapter.cancelDiscovery();
m_BTAdapter.startDiscovery();
long longStart = System.currentTimeMillis(),
longTimer;
boolean bDone = false;
while (m_BTAdapter.isDiscovering() && !bDone)
{
longTimer = System.currentTimeMillis();
//bDone = (longTimer - longStart) < 5000;
}
bEnable = m_BTArrayAdapter.getCount() > 0;
spinnerBluetooth.setEnabled(bEnable);
buttonConnect.setEnabled(bEnable);
buttonSearch.setEnabled(true);
Hey ladies and gents,
I'm new to your forums, seems it will be a helpful resource as I undertake this new project. I'm not new to programming, but i'm rusty. About 20 years ago I started with Qbasic, in high school i moved on to Visual Studio and C++. But I have been out of it for awhile now.
I started learning a little python to help my dad with his own program. But Decided I wanted to use Android Studio for my own. I have already started looking into tutorials, but have yet to see some information I am looking for. ( Or just don't recognize due to inexperience )
Traditionally, whats best to use for a multiscreen App? I am currently running windows in Fragments. I have a sidescreen that pops out with a menu button (works), windows slide out with options ( works ), when you select the option the window slides away (works) and it brings up the fragment so you can fill in forms (works.)
Inside my Fragments java file I have this
public class ac extends Fragment {
private EditText od_input;
private EditText sp_input;
private EditText hp_input;
private EditText sl_input;
private EditText hl_input;
private EditText return_input;
private EditText vent_input;
private TextView diag_output;
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public ac() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment ac.
*/
// TODO: Rename and change types and number of parameters
public static ac newInstance(String param1, String param2) {
ac fragment = new ac();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
EditText odtext;
EditText idtext;
EditText sptext;
EditText hptext;
EditText sltext;
EditText hltext;
EditText returntext;
EditText venttext;
@override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_ac, container, false);
// NOTE : We are calling the onFragmentInteraction() declared in the MainActivity
// ie we are sending "Fragment 1" as title parameter when fragment1 is activated
if (mListener != null) {
mListener.onFragmentInteraction("Air Conditioning");
}
// Here we will can create click listners etc for all the gui elements on the fragment.
// For eg: Button btn1= (Button) view.findViewById(R.id.frag1_btn1);
// btn1.setOnclickListener(...
//odtext = view.findViewById(R.id.odtext);
//idtext = (EditText) findViewById(R.id.idtext);
//sptext = view.findViewById(R.id.sptext);
//hptext = view.findViewById(R.id.hptext);
//sltext = view. findViewById(R.id.sltext);
//hltext = view.findViewById(R.id.hltext);
//returntext = view.findViewById(R.id.returntext);
//venttext = view.findViewById(R.id.venttext);
//TextView diagtext = view.findViewById(R.id.diagtext);
//diagtext.setText((CharSequence) odtext);
return view;
}
@override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// NOTE : We changed the Uri to String.
void onFragmentInteraction(String title);
}
}
Firstly, yes there is a lot of useless crapification going on. Was running different experiments and have not fully cleaned up yet.
But, as people type in the field I want to capture the inputs. Does this require a Listener? Can you capture as they type or do I need a button (Really, Really don't want a button)?
Also, I am unfamiliar with the layout of the java.
Oncreate is when the program boots up?
onCreateview is when the Fragment is booted up?
onattach is when the main activity is associated?
ondetach is when its associated from activity?
I don't fully understand yet where the best place is to add stuff, would it be after onattach?
Thanks for pointing me in the right directions guys.
Chris W.
Hi,
First, a disclaimer.
I am a Java and xposed noob. My background is in embedded C development so I can get by with some simple Java code and thanks to the great tutorials online I have been able to put together an xposed module but I'm struggling with a problem that is beyond my abilities now and am reaching out to the community for help.
Next, the background.
I have an Android head unit in my car. There is an app that provides me with CarPlay functionality but none of the controls on the steering wheel work with the app. When I analysed the code I found that they handle all of their button inputs using proprietary methods that do not inject an event into any input streams. I wrote an xposed module to hook the button press methods and then inject a proper input into one of the event streams.
Initially I tried to use the command line 'input' command to do this but since it is a Java app and takes about 1s to load it was too slow. My only other option was to create a virtual device on an input stream that I could then use to inject keypresses through the hooked method. To create a virtual device I needed to write C code that my xposed module would be able to access through the JNI. Long story short, after some pain I was able to get the native library integrated into the project and compiling using the NDK.
Finally, the problem.
When I was using the module without the native library it worked but just with a large delay because of the time it takes to load the 'input' java app. I was able to see logs from the module in the logcat as I hooked the method and as I went through the various actions within the hook.
As soon as I introduce the native library though the entire xposed module just stops running completely. I do not get any logs from the module even though I have installed, activated and rebooted. It shows up in the xposed installer but it just does nothing. The funny thing is that this happens even if I make no reference whatsoever to any native functions within the library. All I need to do to kill the module is to build it with the System.loadlibrary line in the Main.java uncommented. As soon as I comment that piece of code out the module starts to hook the function and output logs again. Below is the code from the Main.Java that I am referring to. I am happy to make any manifest, C and gradle files available too. Looking for any ideas as to why the module dies completely as soon as I include this...
Code:
package projects.labs.spike.zlink_xposed_swc;
import de.robv.android.xposed.XposedBridge;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.IXposedHookZygoteInit;
import de.robv.android.xposed.XSharedPreferences;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import de.robv.android.xposed.XposedHelpers;
import android.app.AndroidAppHelper;
import android.content.Intent;
import android.os.Bundle;
import android.content.Context;
/* shellExec and rootExec methods */
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ByteArrayOutputStream;
import android.view.KeyEvent;
import android.media.AudioManager;
public class Main implements IXposedHookLoadPackage {
public static final String TAG = "ZLINK_XPOSED ";
public static void log(String message) {
XposedBridge.log("[" + TAG + "] " + message);
}
//public native int CreateVirtualDevice();
//public native int SendPrev();
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
log("handleLoadPackage: Loaded app: " + lpparam.packageName);
if (lpparam.packageName.equals("com.syu.ms")) {
findAndHookMethod("module.main.HandlerMain", lpparam.classLoader, "mcuKeyRollLeft", new XC_MethodHook() {
@Override
protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
// previous
log("PREVKEYHIT");
//rootExec("input keyevent 88");
log("EVENTSENT");
//Below was trying to use media keys which zlink never responded to...
/* Context context = (Context) AndroidAppHelper.currentApplication();
AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PREVIOUS);
mAudioManager.dispatchMediaKeyEvent(event);
KeyEvent event2 = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS);
mAudioManager.dispatchMediaKeyEvent(event2);*/
//Below is the failed broadcast intent method...
/*Context mcontext = (Context) AndroidAppHelper.currentApplication();
Intent i = new Intent("com.android.music.musicservicecommand");
i.putExtra("command", "pause");
mcontext.sendBroadcast(i);*/
}
});
}
}
public static String rootExec(String... strings) {
String res = "";
DataOutputStream outputStream = null;
InputStream response = null;
try {
Process su = Runtime.getRuntime().exec("su");
outputStream = new DataOutputStream(su.getOutputStream());
response = su.getInputStream();
for (String s : strings) {
s = s.trim();
outputStream.writeBytes(s + "\n");
outputStream.flush();
}
outputStream.writeBytes("exit\n");
outputStream.flush();
try {
su.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
res = readFully(response);
} catch (IOException e) {
e.printStackTrace();
} finally {
Closer.closeSilently(outputStream, response);
}
return res;
}
public static String readFully(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = 0;
while ((length = is.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
return baos.toString("UTF-8");
}
[COLOR="Red"] static {
System.loadLibrary("native-lib");
}[/COLOR]
}
The issue with native library is quite strange and I cannot help with it as my experience with native libs is zero.
But maybe try a different method of injecting media key events.
Create a method:
Code:
void injectKey(int keyCode) {
try {
final long eventTime = SystemClock.uptimeMillis();
final InputManager inputManager = (InputManager)
mContext.getSystemService(Context.INPUT_SERVICE);
int flags = KeyEvent.FLAG_FROM_SYSTEM;
XposedHelpers.callMethod(inputManager, "injectInputEvent",
new KeyEvent(eventTime - 50, eventTime - 50, KeyEvent.ACTION_DOWN,
keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, flags,
InputDevice.SOURCE_KEYBOARD), 0);
XposedHelpers.callMethod(inputManager, "injectInputEvent",
new KeyEvent(eventTime - 50, eventTime - 25, KeyEvent.ACTION_UP,
keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, flags,
InputDevice.SOURCE_KEYBOARD), 0);
} catch (Throwable t) {
// something went wrong
XposedBridge.log(t.getMessage());
}
}
Then just do: injectKey(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
And maybe try playing with different KeyEvent flags and attrs.
Thanks so much for this suggestion! Any idea if this injects at a java level or if it depends on there being a keyboard input device available on one of the /dev/input/eventX streams? The android device that I am using has no keyboard available on any of those input streams. Will give it a try nonetheless
C3C076 said:
The issue with native library is quite strange and I cannot help with it as my experience with native libs is zero.
But maybe try a different method of injecting media key events.
Create a method:
Code:
void injectKey(int keyCode) {
try {
final long eventTime = SystemClock.uptimeMillis();
final InputManager inputManager = (InputManager)
mContext.getSystemService(Context.INPUT_SERVICE);
int flags = KeyEvent.FLAG_FROM_SYSTEM;
XposedHelpers.callMethod(inputManager, "injectInputEvent",
new KeyEvent(eventTime - 50, eventTime - 50, KeyEvent.ACTION_DOWN,
keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, flags,
InputDevice.SOURCE_KEYBOARD), 0);
XposedHelpers.callMethod(inputManager, "injectInputEvent",
new KeyEvent(eventTime - 50, eventTime - 25, KeyEvent.ACTION_UP,
keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, flags,
InputDevice.SOURCE_KEYBOARD), 0);
} catch (Throwable t) {
// something went wrong
XposedBridge.log(t.getMessage());
}
}
Then just do: injectKey(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
And maybe try playing with different KeyEvent flags and attrs.
Click to expand...
Click to collapse
looxonline said:
Thanks so much for this suggestion! Any idea if this injects at a java level or if it depends on there being a keyboard input device available on one of the /dev/input/eventX streams? The android device that I am using has no keyboard available on any of those input streams. Will give it a try nonetheless
Click to expand...
Click to collapse
Simply use whatever InputDevice that you think should work in your case.
The method basically calls this:
https://android.googlesource.com/pl.../android/hardware/input/InputManager.java#869
which is then propagated to Input Manager Service here:
https://android.googlesource.com/pl...oid/server/input/InputManagerService.java#598
which then calls nativeInjectInputEvent