/* * Copyright (C) 2007 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. */ package jackpal.androidterm; import android.app.Service; import android.graphics.PixelFormat; import android.os.Binder; import android.os.IBinder; import android.content.Intent; import android.util.DisplayMetrics; import android.util.Log; import android.app.Notification; import android.app.PendingIntent; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; import android.widget.Button; import android.widget.ImageButton; import android.widget.LinearLayout; import jackpal.androidterm.emulatorview.TermSession; import jackpal.androidterm.emulatorview.EmulatorView; import jackpal.androidterm.compat.ServiceForegroundCompat; import jackpal.androidterm.util.SessionList; public class TermService extends Service implements TermSession.FinishCallback { /* Parallels the value of START_STICKY on API Level >= 5 */ private static final int COMPAT_START_STICKY = 1; private static final int RUNNING_NOTIFICATION = 1; private ServiceForegroundCompat compat; private SessionList mTermSessions; private WindowManager.LayoutParams mWmParams; private WindowManager mWindowManager; private LinearLayout mFloatLayout; private String TAG = "TermService"; private EmulatorView mFloatTermView; private Button mRestoreButton; private Button mDockingButton; private ImageButton mRestoreImageButton; private ImageButton mDockingImageButton; // private WindowManager.LayoutParams.gravity initGravity public class TSBinder extends Binder { TermService getService() { Log.i("TermService", "Activity binding to service"); return TermService.this; } } private final IBinder mTSBinder = new TSBinder(); @Override public void onStart(Intent intent, int flags) { } /* This should be @Override if building with API Level >=5 */ public int onStartCommand(Intent intent, int flags, int startId) { return COMPAT_START_STICKY; } @Override public IBinder onBind(Intent intent) { Log.i("TermService", "Activity called onBind()"); return mTSBinder; } @Override public void onCreate() { compat = new ServiceForegroundCompat(this); mTermSessions = new SessionList(); /* Put the service in the foreground. */ Notification notification = new Notification(R.drawable.ic_stat_service_notification_icon, getText(R.string.service_notify_text), System.currentTimeMillis()); notification.flags |= Notification.FLAG_ONGOING_EVENT; Intent notifyIntent = new Intent(this, Term.class); notifyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notifyIntent, 0); notification.setLatestEventInfo(this, getText(R.string.application_terminal), getText(R.string.service_notify_text), pendingIntent); compat.startForeground(RUNNING_NOTIFICATION, notification); Log.d(TermDebug.LOG_TAG, "TermService started"); return; } @Override public void onDestroy() { compat.stopForeground(true); for (TermSession session : mTermSessions) { /* Don't automatically remove from list of sessions -- we clear the * list below anyway and we could trigger * ConcurrentModificationException if we do */ session.setFinishCallback(null); session.finish(); } mTermSessions.clear(); return; } public SessionList getSessions() { return mTermSessions; } public void createFloatView() { mWmParams = new WindowManager.LayoutParams(); //获取WindowManagerImpl.CompatModeWrapper mWindowManager = (WindowManager) getApplication().getSystemService(getApplication().WINDOW_SERVICE); //设置window type mWmParams.type = WindowManager.LayoutParams.TYPE_PHONE; //设置图片格式,效果为背景透明 // mWmParams.format = PixelFormat.RGBA_8888; mWmParams.format = PixelFormat.TRANSLUCENT; mWmParams.alpha = 0.8f; //设置浮动窗口不可聚焦(实现操作除浮动窗口外的其他可见窗口的操作) mWmParams.flags = // LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE // LayoutParams.FLAG_NOT_TOUCHABLE ; //调整悬浮窗显示的停靠位置为左侧置顶 mWmParams.gravity = Gravity.LEFT | Gravity.TOP; // 以屏幕左上角为原点,设置x、y初始值 mWmParams.x = 0; mWmParams.y = 0; /*// 设置悬浮窗口长宽数据 mWmParams.width = 200; mWmParams.height = 80;*/ //设置悬浮窗口长宽数据 // mWmParams.width = WindowManager.LayoutParams.WRAP_CONTENT; // mWmParams.height = WindowManager.LayoutParams.WRAP_CONTENT; //设置悬浮窗口长宽数据 mWmParams.width = mWindowManager.getDefaultDisplay().getWidth(); mWmParams.height = mWindowManager.getDefaultDisplay().getHeight() / 2; LayoutInflater inflater = LayoutInflater.from(getApplication()); //获取浮动窗口视图所在布局 mFloatLayout = (LinearLayout) inflater.inflate(R.layout.float_layout, null); //添加mFloatLayout mWindowManager.addView(mFloatLayout, mWmParams); Log.i(TAG, "mFloatLayout-->left" + mFloatLayout.getLeft()); Log.i(TAG, "mFloatLayout-->right" + mFloatLayout.getRight()); Log.i(TAG, "mFloatLayout-->top" + mFloatLayout.getTop()); Log.i(TAG, "mFloatLayout-->bottom" + mFloatLayout.getBottom()); //浮动Terminal mFloatTermView = (EmulatorView) mFloatLayout.findViewById(R.id.term_view); if (!getSessions().isEmpty()) { mFloatTermView.attachSession(getSessions().get(0)); DisplayMetrics metrics = new DisplayMetrics(); mWindowManager.getDefaultDisplay().getMetrics(metrics); mFloatTermView.setDensity(metrics); } mFloatLayout.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); Log.i(TAG, "Width/2--->" + mFloatTermView.getMeasuredWidth() / 2); Log.i(TAG, "Height/2--->" + mFloatTermView.getMeasuredHeight() / 2); mRestoreButton = (Button) mFloatLayout.findViewById(R.id.restore_button); mRestoreButton.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View view) { // closeFloatWindow(); if (mWindowManager != null && mFloatLayout != null) { mWindowManager.removeView(mFloatLayout); } startActivity(new Intent(getApplication(), Term.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); } }); mDockingButton = (Button) mFloatLayout.findViewById(R.id.docking_button); mDockingButton.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { if ((mWmParams.gravity & Gravity.TOP) == Gravity.TOP) { mWmParams.gravity &= ~Gravity.TOP; mWmParams.gravity |= Gravity.BOTTOM; mDockingButton.setText("DOCKING TOP"); } else if ((mWmParams.gravity & Gravity.BOTTOM) == Gravity.BOTTOM) { mWmParams.gravity &= ~Gravity.BOTTOM; mWmParams.gravity |= Gravity.TOP; mDockingButton.setText("DOCKING BOTTOM"); } mWindowManager.updateViewLayout(mFloatLayout, mWmParams); } }); mRestoreImageButton = (ImageButton) mFloatLayout.findViewById(R.id.restore_imagebutton); mRestoreImageButton.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View view) { // closeFloatWindow(); if (mWindowManager != null && mFloatLayout != null) { mWindowManager.removeView(mFloatLayout); } startActivity(new Intent(getApplication(), Term.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); } }); mDockingImageButton = (ImageButton) mFloatLayout.findViewById(R.id.docking_imagebutton); mDockingImageButton.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { if ((mWmParams.gravity & Gravity.TOP) == Gravity.TOP) { mWmParams.gravity &= ~Gravity.TOP; mWmParams.gravity |= Gravity.BOTTOM; mDockingImageButton.setImageResource(R.drawable.expander_ic_maximized); } else if ((mWmParams.gravity & Gravity.BOTTOM) == Gravity.BOTTOM) { mWmParams.gravity &= ~Gravity.BOTTOM; mWmParams.gravity |= Gravity.TOP; mDockingImageButton.setImageResource(R.drawable.expander_ic_minimized); } mWindowManager.updateViewLayout(mFloatLayout, mWmParams); } }); // //设置监听浮动窗口的触摸移动 // mFloatTermView.setOnTouchListener(new View.OnTouchListener() { // // @Override // public boolean onTouch(View v, MotionEvent event) { // // TODO Auto-generated method stub // //getRawX是触摸位置相对于屏幕的坐标,getX是相对于按钮的坐标 // mWmParams.x = (int) event.getRawX() - mFloatTermView.getMeasuredWidth() / 2; // //Log.i(TAG, "Width/2--->" + mFloatView.getMeasuredWidth()/2); // Log.i(TAG, "RawX" + event.getRawX()); // Log.i(TAG, "X" + event.getX()); // //25为状态栏的高度 // mWmParams.y = (int) event.getRawY() - mFloatTermView.getMeasuredHeight() / 2 - 25; // // Log.i(TAG, "Width/2--->" + mFloatView.getMeasuredHeight()/2); // Log.i(TAG, "RawY" + event.getRawY()); // Log.i(TAG, "Y" + event.getY()); // //刷新 // mWindowManager.updateViewLayout(mFloatLayout, mWmParams); // return false; // } // }); // // mFloatTermView.setOnClickListener(new View.OnClickListener() { // // @Override // public void onClick(View v) { // // TODO Auto-generated method stub // Toast.makeText(TermService.this, "onClick", Toast.LENGTH_SHORT).show(); // } // }); } public void onSessionFinish(TermSession session) { mTermSessions.remove(session); } }