Saturday, December 29, 2018

Tạo activity có màn hình trong suốt



Ta muốn một activity chạy trên màn hình chính mà có nền trong suốt, có thể ấn được vào các icon của ứng dụng phía sau để chạy.
Copy đoạn sau vào trong thẻ values, file styles.xml.
<style name="Theme.Transparent" parent="android:Theme">
<item name="android:windowIsTranslucent">true</item>
<itemname="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowCloseOnTouchOutside">false</item>
<item name="android:backgroundDimEnabled">false</item>
 </style>
Thêm vào khai báo class.
android:theme="@style/Theme.Transparent"

Bây giờ trong class, copy vào dưới
setContentView();
WindowManager.LayoutParams wlp = getWindow().getAttributes();
         wlp.dimAmount = 0;
         wlp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS

|WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;

getWindow().setAttributes(wlp);

Activity bây giờ sẽ nổi ở giữa màn hình, muốn căn chỉnh nó lên trên đầu chẳng hạn, ta thêm đoạn sau vào trên setContentView();
WindowManager.LayoutParams wmlp = getWindow().getAttributes();
         wmlp.width = LayoutParams.WRAP_CONTENT;
         wmlp.gravity = Gravity.TOP | Gravity.CENTER;
Trên một số điện thoại như của Samsung, màn hình phía sau vẫn bị khoá, không chạm để mở ứng dụng khác được. Nên ta có thể dùng service để làm, nó luôn nổi và không ảnh hưởng tới màn hình phía sau.

Cập nhật activity từ service



Để cập nhật activity từ activity khác, ta dùng startActivityForResult để làm, với service ta dùng cách sau.
Giả sử ta cần nhận một String chuyển về từ service và set nó vào textView t.
Khai báo lên trên đầu class.
BroadcastReceiver receiver;
TextView t;
Copy đoạn sau vào dưới setcontentView.
IntentFilter filter = new IntentFilter();
filter.addAction("com.example.vidu");
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
 //UI update here
String b = intent.getStringExtra(service.ve);
t.setText(b);
}
};
registerReceiver(receiver,filter);
Tại service ta khai báo lên trên.
static String ve="";
Copy vào trong onCreate.
String chuyenve= "Đây là dòng chữ đưa về";
Intent local = new Intent();
   local.setAction("com.example.vidu");
     local.putExtra(ve, chuyenve);
     sendBroadcast(local);
Nhớ khai báo service trong file Manifest.xml và hủy đi khi thoát class.
@Override
    protected void onDestroy() {
super.onDestroy();
        
    }

Mở lại ứng dụng khi ấn nút Back


Bình thường nếu ta không làm gì, ấn nút back sẽ khiến màn hình hiện tại bị thoát. Nếu ta muốn vô hiệu hóa nút back, ta dùng dòng sau.
@Override
    public void onBackPressed() {

} 
Chú ý là bên trong không có dòng super.onBackPressed(); 
Cách này sẽ khiến nút back bị trơ, không có phản ứng gì, nếu người dùng đang ở trong màn hình application, bình thường ấn nút back sẽ quay về màn hình home, nếu bị vô hiệu hóa, sẽ phải ấn nút home mới quay về được. 
Ta muốn ứng dụng không bị thoát khi ấn nút back, và vẫn quay lại màn hình home được, ta làm như sau. 
Thêm các dòng sau vào trong lệnh onBackPressed()
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startMain.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startMain.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startMain.putExtra("ID_TimeLeft", String.valueOf(0));
startActivity(startMain);
finish();
Thêm đoạn lệnh sau vào trên ngoặc đóng cuối cùng.
@Override
    public void onStop() {
         super.onStop();
    Intent i=new Intent(this,MainActivity.class);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    i.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
    i.putExtra("ID_TimeLeft",String.valueOf(0));
    startActivity(i);
  }
Tức là ta mở lại class Main ngay khi thoát nó, đồng thời trở về màn hình home.

Chạy ứng dụng liên tục trên màn hình chính.


Nếu ta có một ứng dụng cần hiển thị liên tục trên màn hình chính, ta cần kiểm tra để nếu vì lý do nào đó nó bị chuyển vào background, như người dùng ấn nút home chẳng hạn, thì ta lại đưa nó ra. 
Tạo một service như sau.
public class newse extends Service {
 private static final int INTERVAL = 3000; // poll every 3 secs
 private static final String YOUR_APP_PACKAGE_NAME = "com.example.vidu";
 private static boolean stopTask;
private PowerManager.WakeLock mWakeLock;
 @Override
 public void onCreate() {
     super.onCreate();
  stopTask = false;
final ActivityManager activityManager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
        // Start your (polling) task
    TimerTask task = new TimerTask() {
     @Override
     public void run() {
         // If you wish to stop the task/polling
     if (stopTask){
       this.cancel();
     }
List<ActivityManager.RunningAppProcessInfo> tasks = activityManager.getRunningAppProcesses();
String foregroundTaskPackageName = tasks.get(0).processName;
// Check foreground app: If it is not in the foreground... bring it!
if (!foregroundTaskPackageName.equals(YOUR_APP_PACKAGE_NAME)) {
Intent LaunchIntent = getPackageManager()
                          .getLaunchIntentForPackage(YOUR_APP_PACKAGE_NAME);
                 startActivity(LaunchIntent);
             }
            }
        };
  Timer timer = new Timer();
   timer.scheduleAtFixedRate(task, 0, INTERVAL);
    }
    @Override
    public void onDestroy(){
        stopTask = true;
        if (mWakeLock != null)
            mWakeLock.release();
        super.onDestroy();
    }
    @Override
    public IBinder onBind(Intent intent) {
         // TODO Auto-generated method stub
         return null;
    }
}
Chú ý String package phải đúng như gói ứng dụng của bạn.Khai báo service vào trong file AndroidManifest.xml, trên dòng </application> cuối cùng.
<service
android:name=".newse"
android:enabled="true"
android:exported="false"/>
Tại class cần duy trì hiển thị, thêm các dòng sau lên trên ngoặc đóng dưới cùng.
@Override
    public void onWindowFocusChanged(boolean hasFocus) {
         super.onWindowFocusChanged(hasFocus);
         if (!hasFocus) {
    Intent intent = new Intent(this, newse.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    startService(intent);          }
         }
    }

Tức là mỗi khi ứng dụng bị ra khỏi màn hình chính, ta lập tức đưa nó trở lại. Sau khi chạy trở lại xong, nếu ta không tắt service, điện thoại sẽ bị hao pin rất nhanh vì service sẽ liên tục kiểm tra cứ 3 giây một lần xem ứng dụng có trên top hay không.Vậy ta sẽ tắt đi sau khi dùng xong.
Intent intent = new Intent(this, newse.class);
         intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
       stopService(intent);
Có thể chỉ cần thêm dòng stopService là được, có khi phải tạo hàm để gọi.Tùy lúc dùng bạn thấy lúc nào cần gọi thì gọi, nói chung cần canh 3 nút back, home và menu là được. Cũng có thể chỉ dùng đoạn code trong lõi service.
  final ActivityManager activityManager=(ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> tasks = activityManager.getRunningAppProcesses();
String foregroundTaskPackageName = tasks.get(0).processName;
 if(!foregroundTaskPackageName.equals(YOUR_APP_PACKAGE_NAME)) {
Intent LaunchIntent = getPackageManager()
.getLaunchIntentForPackage(YOUR_APP_PACKAGE_NAME);
startActivity(LaunchIntent);
}
Tuy nhiên khi dùng trực tiếp thế này nhiều khi nó không chạy!

Không cho thoát ứng dụng


Có những ứng dụng cần chạy liên tục để thực hiện một tác vụ nào đó, ta cần giữ nó không bị thoát. Ta có thể dùng onStop để mở lại ngay khi bị thoát.
@Override
    public void onStop() {
         super.onStop();
    Intent i=new Intent(this,MainActivity.class);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    i.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
    i.putExtra("ID_TimeLeft",String.valueOf(0));
    startActivity(i);
  }
Hoặc ta tạo một hàm kiểm tra như sau.
public static boolean isRunning(Context context) {
 ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
 for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if(activity.class.getName().equals(service.service.getClassName())){
       return true;
      }
  }
   return false;
} 
Thêm đoạn code sau vào trên ngoặc đóng cuối cùng.
boolean chay=true;
@Override
    public void onWindowFocusChanged(boolean hasFocus) {
         super.onWindowFocusChanged(hasFocus);
         if (!hasFocus) {
             chay=isRunning(this);
             if(chay==false){
              finish();
         Intent i=new Intent(this,activity.class);
            startActivity(i);
            chay=true;

        } 
Bây giờ mỗi khi bị thoát, ứng dụng sẽ tự mở lại.