14_自定义对话框_40
1、画图两个对话框的样子;
2、写大体逻辑代码;
showLostFindDialog();//进入手机防盗的对话框;
isSetupPwd();//判断是否设置过密码,用到共享偏好。
private boolean isSetupPW(){
String password = sp.getString("password", null);
return !TextUtils.isEmpty(password);
}
showSetupPwdDialog();
showEnterDialog();
布局文件(dialog_setup.password.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="300dip"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="300dip"
android:layout_height="40dip"
android:background="#66ff6600"
android:gravity="center"
android:text="设置密码"
android:textColor="#000000"
android:textSize="20sp" />
<EditText
android:id="@+id/et_setup_pwd"
android:layout_width="280dip"
android:layout_height="wrap_content"
android:hint="请输入密码" />
<EditText
android:id="@+id/et_setup_pwd_confirm"
android:layout_width="280dip"
android:layout_height="wrap_content"
android:hint="请再输入密码" />
<LinearLayout
android:layout_width="280dip"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >
<Button
android:id="@+id/ok"
android:layout_width="140dip"
android:layout_height="wrap_content"
android:text="确定" >
</Button>
<Button
android:id="@+id/cancel"
android:layout_width="140dip"
android:layout_height="wrap_content"
android:text="取消" >
</Button>
</LinearLayout>
</LinearLayout>
showSetupPwdDialog();对话框的代码:
确定按钮:
String password= et_setup_pwd.getText().toString().trim();
String password_confirm = et_setup_pwd_confirm.getText().toString().trim();
if(TextUtils.isEmpty(password)||TextUtils.isEmpty(password_confirm)){
Toast.makeText(getApplicationContext(), "密码为空", 0).show();
return ;
}
if(password.equals(password_confirm)){
//密码相同-保存并且进入手机防盗页面
Editor editor = sp.edit();
editor.putString("password", password);
editor.commit();
dialog.dismiss();
//进入手机防盗页面
Log.i(TAG, "密码已经保存,进入手机防盗页面");
}else{
Toast.makeText(getApplicationContext(), "密码不一致", 0).show();
return ;
}
取消按钮
前提dialog = builder.show();
dialog.dismiss();
3、设置密码对话框部署并找出不好看的原因,并且修改;
修改大小小于父控件;
4、设置密码对话框变得好看。加ID,并实现点击代码逻辑;
初始化ID、
取消事件--dialog抽取出去:
确定事件:
5、拷贝进入密码对话框布局文件,并命名为:dialog_enter_password.xml
6、拷贝进入密码对话框的代码并修改
7、总结:不同的布局文件里面各自的ID是可以重名的
但是同一个布局文件里,相同的ID不允许重名的;
15_自定义对话框的细节_10
1、创建2.3模拟器展示对话框(有黑背景),4.12和2.3的区别,并说明原因
2、解决在2.3对话框有黑背景的问题
设置背景为白:android:background="#ffffff"
alertDialog = builder.create();
alertDialog.setView(view, 0, 0, 0, 0);
alertDialog.show();
16_密码的MD5加密_24
本知识点需要:手机能共享网络
1、为什么要加密--不加密的不安全
知识拓展:
root权限
买过来的手机是没有root权限的;
Root权限是linux系统的超级管理员权限;
如果你的手机刷机了,那就有root权限
模拟器能看到data/data里的数据,是为了方便开发者
没有root权限的手机是看不到data/data
有root权限的符号:#
没有root权限的符号:$
查看config.xml命令
cat config.xml
2、md5算法
不可逆的:原文--》密文、用系统的API可以实现;
123456 ---密文
1987 ----密文;
算法步骤:
1、用每个byte去和11111111做与运算并且得到的是int类型的值:
byte & 11111111;
2、把int 类型转成 16进制并返回String类型;
3、不满八个二进制位就补全;
public static void main(String[] args) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("md5");
String password = "123456";
byte [] result = digest.digest(password.getBytes());
StringBuffer buffer = new StringBuffer();
for(byte b : result){
int nuber = b & 0xff;
String str = Integer.toHexString(nuber);
if(str.length()==1){
buffer.append("0");
}
buffer.append(str);
}
//这就是MD5加密得到的值
System.out.println(buffer);
}
没有事先准备的算法异常;
4、网站验证算法是否正确(www.cmd5.com)、加密再加密再演示
5、密码加盐
6、合并代码进入工程(MD5Utils)方法名:encode
7、删除config.xml (rm *),并演示;
17_手机防盗设置向导的第一个界面_34
准备:需要谷歌文档
1、演示百度输入法设置向导
2、创建LostFindActivity,在HomeActivity激活并可以进入;
confied判断是否用户设置向导,如果没有就进入设置向导;
3、创建Setup1Activity
4、自定义标题样式命名:text_title_style
5、自定义文本样式text_content_style(图片名star_big_on)。
6、小点图片(presence_online、presence_invisible)
18_自定义按钮状态背景_15
1、在android-16\data\res\values\styles.xml看一下系统定义的Button样式,看一下低版本和版本的区别
2、看一下帮助文档(Develog/App Resources/Resource Types/drawbale/)Button如何自定义;
创建drawble目录 ,拷贝文档中定义的案例;
3、用美图秀秀自定义按钮背景(50*50),命名:button.xml
4、用别人的图片:button_bg.xml,
5、用自己准备好的图片;
6、把做好的背景设置到设置密码对话框和输入密码对话框;
7、进模拟器设置里设置显示边框。
19_4个设置向导的UI完成和跳转事件_30
1、讲出几个布局文件的共性;
2、自定义下一个、上一个按钮样式;
3、创建多个Setup2Acitvity、Setup3Acitvity、Setup4Acitvity;并在功能清单注册;
4、定义点击事件在样式里:
5、代码里实现;
6、从手机防盗页面到第一个设置页面Intent;
7、拷贝手机防盗页面,并完成跳转;
20_手机防盗页面的完成_15
21_shape形状资源_13
1、前提:重新进入设置向导控件没点击效果reEnterSetup
2、看文档Develop/API Guides/App Resources/Drawable/Shape Drawable
单词:corners : 角 ; gradient :梯度; solid:固定的; stroke: 边框--可以做下划线
Rectangle : 矩形;dash :破折号 gap:间隙;
3、拷贝实例代码,文件命名(gradient_box.xml)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="5dip"/>
<gradient android:startColor="#ff0000"
android:endColor="#00ff0000"/>
<solid android:color="#ffffff" />
<stroke android:width="3dip" android:color="#000000" android:dashGap="5dip"
android:dashWidth="5dip"/>
</shape>
4、默认状态gradient_box.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="5dip"/>
<solid android:color="#ffffff" />
</shape>
5、按下去状态状态gradient_box_press.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="5dip"/>
<solid android:color="#22000000" />
</shape>
6、把两个状态整合在shape_bg.xml
7、并使用
22_设置向导页面的切换动画_12
1、anim
2、下一步动画 位移动画
解释-100%p p:代表父窗体,100%:代表整个窗体,-:代码向左移动;
tran_out.xml
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:toXDelta="-100%p"
android:fromYDelta="0"
android:toYDelta="0"
android:duration="500"
>
</translate>
Tran_in.xml
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="100%p"
android:toXDelta="0"
android:fromYDelta="0"
android:toYDelta="0"
android:duration="500"
>
</translate>
3、使用动画:
overridePendingTransition(R.anim.tran_in, R.anim.tran_out);
上一步动画
Tran_pre_out.xm;
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:toXDelta="100%p"
android:fromYDelta="0"
android:toYDelta="0"
android:duration="500"
>
</translate>
Tran_pre_in.xm
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="-100%p"
android:toXDelta="0"
android:fromYDelta="0"
android:toYDelta="0"
android:duration="500"
>
</translate>
4、使用动画:
overridePendingTransition(R.anim.tran_pre_in, R.anim.tran_pre_out);
知识拓展:
有些手机上无法出现动画:是因为把播放动画的功能关闭了,为什么关闭呢,是为什么省点;
Android手机省电的几个技巧:
1.不要用动态的壁纸;
2.屏幕亮度调低一些;
3.3G网络关闭使用,2G网络,当然是不需要上网的情况下;
4.关闭手机执行动画;
5.经常杀一下后台的应用;
23_屏幕的滑动切换&s抽取父类_39
1、在Setup1Activity定义一个手势识别器;GestureDetector
2、并画图分析
3、抽取next()--->shownext();代码
public class Setup1Activity extends Activity {
//1、声明一个手势识别器
private GestureDetector gestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup1);
//2、初始化一个手势识别器
gestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener(){
//当时手指在屏幕上滑动时调用的方法
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
if((e2.getRawX() - e1.getRawX()) > 200){
//显示上一个页面:从左向右滑动
System.out.println("显示上一个页面");
return true;
}
if((e1.getRawX() - e2.getRawX()) > 200){
//显示下一个页面:从右向左滑动
shownext();
System.out.println("显示下一个页面");
return true;
}
return super.onFling(e1, e2, velocityX, velocityY);
}
});
}
//3、用手势识别器,检查屏幕上的手势识别器
@Override
public boolean onTouchEvent(MotionEvent event) {
gestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
public void next(View view){
shownext();
}
private void shownext() {
Intent intent = new Intent(this,Setup2Activity.class);
startActivity(intent);
finish();//关闭当前的页面
overridePendingTransition(R.anim.tran_in, R.anim.tran_out);
}
}
4、使用注册
5、抽取到基类BaseSetupActivity
6、屏蔽竖值方向的滑动;
if(Math.abs((e2.getRawY() - e1.getRawY())) >100){
Toast.makeText(getBaseContext(), "不能这样滑动", 0).show();
return true;
}
7、屏蔽滑动慢
if(Math.abs(velocityX)< 200){
Toast.makeText(getBaseContext(), "滑动有些慢哥们", 0).show();
return true;
}
24_绑定sim卡_23
手机防盗最核心的就是绑定sim卡;
为什么不绑定手机号码呢?
因为有些SIM卡里没有写入手机号码,比如移动的卡和联通的卡等等。
1、读取SiM卡的串口号代码:
siv_setup2_bindsim.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(siv_setup2_bindsim.isChecked()){
Editor editor = sp.edit();
editor.putString("sim", null);
editor.commit();
siv_setup2_bindsim.setChecked(false);
}else{
//得到SiM卡的串口号
String sim = tm.getSimSerialNumber();
Editor editor = sp.edit();
editor.putString("sim", sim);
editor.commit();
siv_setup2_bindsim.setChecked(true);
}
}
});
TelephonyManager 加权限
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
2、记录串口号;
3、在基类BaseSetupActivtiy 初始化共享偏好;
4、用命令查看数据是否设置成功;
5、在Setup2Activity演示super.onCreate()的作用
25_检查手机是否更换sim卡_23
原理:1、sim插入一般会拔掉电源,会导致开启重启;2、侧面卡槽也会导致手机重启--重启通讯模块;
1、创建新包com.itheima.mobilesafe.receiver 和新类(BootCompleteReceiver)
功能清单文件:
<receiver android:name="com.itheima.mobilesafe.receiver.BootCompleteReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
2、权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
接收信息
public class BootCompleteReceiver extends BroadcastReceiver {
private SharedPreferences sp;
private TelephonyManager tm;
@Override
public void onReceive(Context context, Intent intent) {
//检查当前的手机sim,读取原来绑定的sim卡,如果发现两个卡不一样,说明手机可能被盗。需要偷偷的发短信报警;
sp = context.getSharedPreferences("config", context.MODE_PRIVATE);
String bindsim = sp.getString("sim", "")+"a";
tm = (TelephonyManager) context.getSystemService(context.TELEPHONY_SERVICE);
String realsim = tm.getSimSerialNumber();
if(bindsim.equals(realsim)){
//手机卡没有变更,就是你的手机和你的卡;
}else{
//sim卡变更了,发送报警信息;
System.out.println("sim卡变更了,发送报警信息");
}
}
}
3、关闭模拟器,重启演示;
26_读取手机联系人_40
authorities :当局
1、到开发环境data/data/目录下 com.android.providers.contacts/databases/导出到左面contacts2.db
2、用工具打开数据库关心三张表:raw_contacts、data、mimetypes
3、创建一个新的工程去读取联系人SelectContact
4、创建一个得到所有联系人的方法 getContactInfos();----表的路径
List<Map<String, String>> data = new ArrayList<Map<String, String>>();
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri datauri = Uri.parse("content://com.android.contacts/data");
5、查询raw_contact表 取联系人id
Cursor cursor = resolver.query(uri, new String[] { "contact_id" },
null, null, null);
6、得到联系人的ID
while (cursor.moveToNext()) {
String id = cursor.getString(0);
System.out.println("联系人的id为:" + id);
}
7、查表data表到联系人的姓名和电话号码
Map<String, String> map = new HashMap<String, String>();
// 查询data表 把当前联系人的姓名和电话new String[]{"data1","mimetype"}数据给取出来.
Cursor dataCursor =
resolver.query(datauri, new String[]{"data1","mimetype"},
"raw_contact_id=?", new String[] { id }, null);
8、添加数据到map集合
String data1 = dataCursor.getString(0);
String mimetype = dataCursor.getString(1);
if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) {
System.out.println("电话:" + data1);
map.put("phone", data1);
} else if ("vnd.android.cursor.item/name".equals(mimetype)) {
System.out.println("姓名:" + data1);
map.put("name", data1);
}
9、读取联系人需要加权限
<uses-permission android:name="android.permission.READ_CONTACTS"/>
知识回顾
URI(统一资源标识符)的使用方法
为系统的每一个资源给其一个名字,比方说通话记录。
1、每一个ContentProvider都拥有一个公共的URI,这个URI用于表示这个ContentProvider所提供的数据。
2、Android所提供的ContentProvider都存放在android.provider包中。 将其分为A,B,C,D 4个部分:
A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;"content://"
B:URI 的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的 类名。这个标识在 元素的 authorities属性中说明:一般是定义该ContentProvider的包.类的名称;"content://hx.android.text.myprovider"
C:路径,不知道是不是路径,通俗的讲就是你要操作的数据库中表的名字,或者你也可以自己定义,记得在使用的时候保持一致就ok了;"content://hx.android.text.myprovider/tablename"
D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部; "content://hx.android.text.myprovider/tablename/#" #表示数据id
----------------------------------------------------------------------------------------------------------------------------------------------------------
自定义组合控件
- 自定义一个View, 继承ViewGroup,比如RelativeLayout
-
编写组合控件的布局文件,在自定义的View中加载
// 将自定义好的布局文件设置给当前的SettingItemView View.inflate(getContext(), R.layout.view_setting_item, this);
-
自定义属性
Root权限
什么是Root权限? Root权限相当于系统管理员权限, 有了root权限,就可以随意修改和删除手机内部的文件.
一般手机购买之后, 都没有root权限. 厂商考虑到安全性因素,不允许用户或者第三方app删除和修改手机的内部文件(当然,sdcard的内容可以随意修改,不需要root权限)
如何获取root权限? 可以用第三方软件,比如刷机大师等. 一键root
有了Root后可以干嘛? 1. 刷机 2. 删除手机内置的app 3. 访问data/data目录的文件,并进行修改
怎么才能知道手机有么有root? 1. 刷机大师(小白用户用此方法) 2. 查看是否可以访问data/data目录,如果可以,就说明已经root了 3. cmd命令行,运行adb shell, 如果显示#,表示已经root, 如果显示$,表示没有root(如果用真机运行,即使root了,也显示$,这时候,运行命令su,可以直接获取管理员权限)
MD5
计算字符串或文件的特征码(数字指纹), 不可逆, 因为任何文件或字符串算出来的md5都是32位!
数据库: 123456->e10adc3949ba59abbe56e057f20f883e 654321->e10adc3949ba59abbe56e057f20f883e
在线破解网站: http://www.cmd5.com/
对MD5进行"加盐"处理, 增强安全性 MD5(password)->MD5(password + 用户昵称 + 用户id...)
.9.png(9-Patch)
通过黑色边线来描述图片的拉伸情况和填充文字的方式 上边线表示图片水平拉伸, 左边线表示垂直拉伸 右边线表示垂直填充区域, 下边线表示水平填充区域
状态选择器(selector)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/function_greenbutton_pressed" android:state_pressed="true"/>//按下的图片
<!-- pressed -->
<item android:drawable="@drawable/function_greenbutton_pressed" android:state_focused="true"/>//获取焦点的图片
<!-- focused -->
<item android:drawable="@drawable/function_greenbutton_normal"/>
<!-- default -->//默认图片
</selector>
<Button
android:background="@drawable/btn_green_selector"
/>//将选择器设置给Button
状态选择器(selector)
md5密码加盐
http://www.blogjava.net/heyang/archive/2010/11/28/339233.html 按:以下还是炒冷饭,如果您对加盐了解就不用往下看了,以免浪费宝贵时间。 如果不了解下文部分细节的话,您可以参考这篇文章:使用MD5对存放在数据库中用户密码进行保护 直接对重要数据进行MD5处理后,反向解密确实难度很大,但还是可以找出破绽的,请看下图: (图片不能显示就文字说明一下) 例如:两个人或多个人的密码相同,通过md5加密后保存会得到相同的结果。破一个就可以破一片的密码。 如果名为李自成的用户可以查看数据库,那么他可以观察到自己的密码和别人的密码加密后的结果都是一样,那么,别人用的和自己就是同一个密码,这样,就可以利用别人的身份登录了。 那么我们以前的加密方法是否对这种行为失效了呢?其实只要稍微混淆一下就能防范住了,这在加密术语中称为“加盐”。具体来说就是在原有材料(用户自定义密码)中加入其它成分(一般是用户自有且不变的因素),以此来增加系统复杂度。当这种盐和用户密码相结合后,再通过摘要处理,就能得到隐蔽性更强的摘要值。下面请见代码: // 对密码进行加盐后加密,加密后再通过Hibernate往数据库里存 String changedPswd=DigestUtils.md5Hex(name+pswd); 就是这样简单,上面代码中盐就是用户名,可以的话还可以用用户注册时的邮件,注册时间等非空信息(如果是空信息这个加盐处理会失效)。 下面是数据库中两个用户的记录,他们的实际登录密码都是123456,但光看用户记录是完全看不出来的。这下别有用心的人打开数据库看到的密码都完全不一样,他以前的手段就失效了。 因为密码是md5处理的密码加用户名,因为用户名都不相同,所以即使密码相同的用户,保存到数据库中密码也是不同的。