somethings basic for bapi badi and user exit

本文介绍了SAP系统中用于增强标准程序功能的三种主要技术:BAPI、BADI 和 USEREXIT 的工作原理及区别。重点阐述了 BADI 和 USEREXIT 在 SAP 标准程序更新时的不同表现,并对比了 BDC 和 BAPI 在处理 SAP 交易时的应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 BAPI - These are published programs which is used to upload data i
nto SAP system.

BADI - This is a program enhancement technique. SAP pr
ovides BADI openings in the standard programs. You need to search for the s
uitable BADI as ur requirement and then do the coding and plug in the progr
am.

USEREXIT - It is also a program enhancement technique. here also u
need to find suitable userexit and code in ur program.

The main diff
bet BADI and USEREXIT is that in USEREXIT u code in the standard SAP progra
m, hence any updation in the version of the standard program will lead to t
he loss of ur coding. But same is not the case of BADI. Here the code remai
ns outside the standard program.

2. Both BDC and BAPI will work. For a
njoi SAP transaction, prefer a BAPI over a BDC

// frameworks/base/services/core/java/com/android/server/wm/ParallelSession.java package com.android.server.wm; import android.app.ActivityOptions; import android.annotation.NonNull; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.content.res.XmlResourceParser; import android.graphics.Rect; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; import android.util.Xml; import android.view.DisplayInfo; import android.view.WindowManager; import android.view.InputChannel; import com.android.server.input.InputManagerService; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.CopyOnWriteArrayList; import java.util.HashSet; import java.util.Set; import com.android.server.wm.ActivityRecord.State; /** * 管理平行视界会话,处理主副屏Activity的生命周期同步和布局 */ public class ParallelSession { private static final String TAG = "ParallelSession_wangw"; private static final boolean DEBUG = true; // 全局会话存储(按任务ID索引) private static final SparseArray<ParallelSession> sSessions = new SparseArray<>(); // 平行应用映射(包名 -> 副屏Activity类名) public static final ArrayMap<String, String> sParallelApps = new ArrayMap<>(); static { Log.i(TAG, "sParallelApps init !"); sParallelApps.put("com.taobao.taobao", "com.taobao.shop.activity.DetailActivity"); sParallelApps.put("com.jingdong.app.mall", "com.jd.lib.productdetail.ProductDetailActivity"); sParallelApps.put("com.alibaba.android.rimet", "com.alibaba.android.rimet.biz.web.WebActivity"); } private final int mTaskId; private ActivityRecord mPrimaryActivity; // 主屏活动 private ActivityRecord mSecondaryActivity; // 副屏活动 private float mSplitRatio = 0.4f; // 分屏比例(默认50%) private WindowState mPrimaryWindow; // 主屏窗口 private WindowState mSecondaryWindow; // 副屏窗口 // 使用原子操作标记防止递归 final AtomicBoolean isDestroying = new AtomicBoolean(false); // 生命周期监听器接口(用于状态同步) public interface LifecycleListener { void onStateChanged(ActivityRecord activity, State state); void onDestroyed(ActivityRecord activity); void onConfigurationChanged(ActivityRecord activity, Configuration newConfig); } // 线程安全的生命周期监听器列表 private final CopyOnWriteArrayList<LifecycleListener> mLifecycleListeners = new CopyOnWriteArrayList<>(); public ParallelSession(ActivityRecord primary) { //if(primary.getTask() == null) return; mTaskId = primary.getTask().mTaskId; //mPrimaryActivity = primary; sSessions.put(primary.getTask().mTaskId, this); setPrimaryActivity(primary); if (DEBUG) Log.d(TAG, "Created new ParallelSession for task: " + primary.getTask().mTaskId +", primary = "+primary.toString()); } public ParallelSession(int taskId, ActivityRecord primary) { //if(primary.getTask() == null) return; mTaskId = taskId; //mPrimaryActivity = primary; sSessions.put(taskId, this); setPrimaryActivity(primary); Log.i(TAG, "Created new ParallelSession for task:" + taskId); } // 设置主屏活动 public void setPrimaryActivity(ActivityRecord primary) { //if (mPrimaryActivity != null && sParallelApps.containsKey(primary.packageName)) { if (primary != null) { Log.w(TAG, "Primary activity != null"); if (!sParallelApps.containsKey(primary.packageName)) { Log.w(TAG, "Primary activity set failed!"); return; } } mPrimaryActivity = primary; //getPrimaryWindow().attach(); if(getWindowStateForRecord(mPrimaryActivity) != null) getWindowStateForRecord(mPrimaryActivity).attach(); linkPrimaryActivities(); if (DEBUG) Log.d(TAG, "Primary activity set: " + primary); } // 设置副屏活动 public void setSecondaryActivity(ActivityRecord secondary) { if (mSecondaryActivity != null) { Log.w(TAG, "Secondary activity already set!"); return; } mSecondaryActivity = secondary; linkSecondaryActivities(); if (DEBUG) Log.d(TAG, "Secondary activity set: " + secondary); } private void linkPrimaryActivities() { // 绑定生命周期事件 if (DEBUG) Log.d(TAG, "linkPrimaryActivities"); mPrimaryActivity.addLifecycleListener(new LifecycleListener() { @Override public void onStateChanged(ActivityRecord activity, State state) { if (DEBUG) Log.d(TAG, "linkPrimaryActivities mPrimaryActivity onStateChanged"); if (state == ActivityRecord.State.PAUSED && mSecondaryActivity != null) { if (DEBUG) Log.d(TAG, "Primary paused, pausing secondary"); // 使用任务调度暂停副屏活动 //mSecondaryActivity.pause(); //mSecondaryActivity.getTask().schedulePauseActivity(mSecondaryActivity); } else if (state == ActivityRecord.State.RESUMED && mSecondaryActivity != null) { if (DEBUG) Log.d(TAG, "Primary resumed, resuming secondary"); if (mSecondaryActivity.isState(ActivityRecord.State.RESUMED)) return; // 使用系统服务恢复副屏活动 //if (mSecondaryActivity.getTask() != null) mSecondaryActivity.getTask().resumeTopActivityUncheckedLocked(null,null); // 异步恢复副屏Activity handler.post(() -> { if (mSecondaryActivity.getTask() != null) { mSecondaryActivity.getTask().resumeTopActivityUncheckedLocked(null, null); } }); //mSecondaryActivity.resume(); } handleFocusChange(mPrimaryWindow); } @Override public void onConfigurationChanged(ActivityRecord activity, Configuration newConfig) { if (DEBUG) Log.d(TAG, "linkPrimaryActivities mPrimaryActivity onConfigurationChanged"); } @Override public void onDestroyed(ActivityRecord activity) { if (isDestroying.getAndSet(true)) { return; // 已经在销毁过程中 } /* if (DEBUG) Log.d(TAG, "linkPrimaryActivities mPrimaryActivity onDestroyed"); if (mSecondaryActivity != null && !mSecondaryActivity.finishing) { if (DEBUG) Log.d(TAG, "Primary destroyed, finishing secondary"); // 使用安全销毁方法 mSecondaryActivity.destroyIfPossible("Primary destroyed"); //mSecondaryActivity.finishIfPossible("Primary destroyed", true); } sSessions.remove(activity.getTask().mTaskId); */ try { if (DEBUG) Log.d(TAG, "linkPrimaryActivities mPrimaryActivity onDestroyed"); if (mSecondaryActivity != null && !mSecondaryActivity.finishing) { // 移除监听器防止回调 mSecondaryActivity.removeLifecycleListener(this); // 延迟销毁副屏Activity handler.postDelayed(() -> { if (!mSecondaryActivity.finishing) { mSecondaryActivity.destroyImmediately("Primary destroyed"); } }, 100); // 100ms延迟确保主Activity完全销毁 } } finally { if(sSessions != null && mSecondaryActivity != null && mSecondaryActivity.getTask() != null) sSessions.remove(activity.getTask().mTaskId); isDestroying.set(false); } } }); } private void linkSecondaryActivities() { // 绑定生命周期事件 if (DEBUG) Log.d(TAG, "linkSecondaryActivities"); // 副屏关闭时同步主屏 mSecondaryActivity.addLifecycleListener(new LifecycleListener() { @Override public void onStateChanged(ActivityRecord activity, State state) { if (DEBUG) Log.d(TAG, "linkSecondaryActivities mSecondaryActivity onStateChanged"); /* if (state == ActivityRecord.State.RESUMED && mPrimaryActivity != null) { if (DEBUG) Log.d(TAG, "Primary resumed, resuming secondary"); if (mPrimaryActivity.isState(ActivityRecord.State.RESUMED)) return; // 使用系统服务恢复副屏活动 if (mPrimaryActivity.getTask() != null) mPrimaryActivity.getTask().resumeTopActivityUncheckedLocked(null,null); //mSecondaryActivity.resume(); } */ handleFocusChange(mSecondaryWindow); } @Override public void onConfigurationChanged(ActivityRecord activity, Configuration newConfig) { if (DEBUG) Log.d(TAG, "linkSecondaryActivities mSecondaryActivity onConfigurationChanged"); } @Override public void onDestroyed(ActivityRecord activity) { if (isDestroying.getAndSet(true)) { return; } /* if (DEBUG) Log.d(TAG, "linkSecondaryActivities mSecondaryActivity onDestroyed"); if (mPrimaryActivity != null && !mPrimaryActivity.finishing) { if (DEBUG) Log.d(TAG, "Secondary destroyed, finishing primary"); // 使用安全销毁方法 mPrimaryActivity.destroyIfPossible("Secondary destroyed"); //mPrimaryActivity.finishIfPossible("Secondary destroyed", true); } sSessions.remove(mPrimaryActivity.getTask().mTaskId); */ try { if (DEBUG) Log.d(TAG, "Secondary destroyed"); if (mPrimaryActivity != null && !mPrimaryActivity.finishing) { // 移除监听器防止回调 mPrimaryActivity.removeLifecycleListener(this); // 延迟销毁主Activity handler.postDelayed(() -> { if (!mPrimaryActivity.finishing) { mPrimaryActivity.destroyImmediately("Secondary destroyed"); } }, 100); } } finally { if(sSessions != null && mPrimaryActivity != null && mPrimaryActivity.getTask() != null) sSessions.remove(mPrimaryActivity.getTask().mTaskId); isDestroying.set(false); } } }); } private Handler handler = new Handler(Looper.getMainLooper()){ @Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg); //todo somethings //if (msg.what == MSG_WHAT) { // 处理消息 //Log.e("CentralSurfacesImpl_wangw", "mHandler2 1 Message received"); //} } }; // 计算主屏显示区域 public Rect getPrimaryBounds(DisplayContent display) { if (DEBUG) Log.d(TAG, "getPrimaryBounds"); if (display == null) { Log.w(TAG, "Null display for primary bounds"); return new Rect(0, 0, 1080, 1920); // 默认值 } DisplayInfo info = display.getDisplayInfo(); Rect bounds = new Rect(0, 0, info.logicalWidth, info.logicalHeight); bounds.right = (int) (bounds.width() * mSplitRatio); // 按比例分割 return bounds; } // 计算副屏显示区域 public Rect getSecondaryBounds(DisplayContent display) { if (DEBUG) Log.d(TAG, "getSecondaryBounds"); if (display == null) { Log.w(TAG, "Null display for secondary bounds"); return new Rect(0, 0, 1080, 1920); // 默认值 } DisplayInfo info = display.getDisplayInfo(); Rect bounds = new Rect(0, 0, info.logicalWidth, info.logicalHeight); bounds.left = (int) (bounds.width() * mSplitRatio); // 按比例分割 return bounds; } public void setSplitRatio(float ratio) { if (DEBUG) Log.d(TAG, "setSplitRatio"); mSplitRatio = Math.max(0.2f, Math.min(0.8f, ratio)); if (mPrimaryActivity != null && mPrimaryActivity.getWindow() != null) { mPrimaryActivity.getTask().reparent(null, true); } if (mSecondaryActivity != null && mSecondaryActivity.getWindow() != null) { mSecondaryActivity.getTask().reparent(null, true); } } public static boolean shouldOpenInSecondary(ActivityRecord caller, ActivityRecord target) {//控制是否在第二界面打开 if (DEBUG) Log.d(TAG, "shouldOpenInSecondary, caller = "+caller+", target = "+target); if (caller == null || !(sParallelApps.containsKey(caller.packageName))) { return false; } return sParallelApps.containsKey(target.packageName); /* if (caller == null || !sParallelApps.containsKey(caller.packageName)) { return false; } String expectedActivity = sParallelApps.get(caller.packageName); return expectedActivity.equals(targetInfo.targetActivity) || expectedActivity.equals(targetInfo.name); */ } /* public static void loadConfigFromFile(File configFile) { if (!configFile.exists()) { Log.w(TAG, "Parallel config file not found: " + configFile); return; } try (FileInputStream fis = new FileInputStream(configFile)) { XmlResourceParser parser = Xml.newPullParser(); parser.setInput(fis, "UTF-8"); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { if (type != XmlPullParser.START_TAG) continue; final String tagName = parser.getName(); if ("parallel-apps".equals(tagName)) { parseParallelApps(parser); } } } catch (IOException | XmlPullParserException e) { Log.e(TAG, "Error loading parallel config", e); } } private static void parseParallelApps(XmlPullParser parser) throws IOException, XmlPullParserException { sParallelApps.clear(); int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type != XmlPullParser.START_TAG) continue; if ("app".equals(parser.getName())) { String pkg = parser.getAttributeValue(null, "package"); String secondary = parser.getAttributeValue(null, "secondary"); if (pkg != null && secondary != null) { sParallelApps.put(pkg, secondary); if (DEBUG) Log.i(TAG, "Added parallel app: " + pkg + " -> " + secondary); } } } } */ // 在 ActivityRecord 类中添加获取 WindowState 的方法 /* public WindowState getWindowState(ActivityRecord record) { // 1. 获取 AppWindowToken final AppWindowToken appWindowToken = record.appWindowToken; if (appWindowToken == null) { return null; } // 2. 获取 WindowToken final WindowToken windowToken = appWindowToken.getWindowToken(); if (windowToken == null) { return null; } // 3. 获取 WindowState for (int i = windowToken.getChildCount() - 1; i >= 0; i--) { final WindowState win = (WindowState) windowToken.getChildAt(i); if (DEBUG) Log.d(TAG, "getWindowState window = " + win); if (win != null && win.mActivityRecord == record) { return win; } } return null; } */ // 正确获取与 ActivityRecord 关联的 WindowState public WindowState getWindowStateForRecord(ActivityRecord record) { WindowManagerService wms = record.mWmService; if (wms == null) { return null; } synchronized (wms.mGlobalLock) { // 方法1:直接通过 token 获取(推荐) WindowState win = wms.mWindowMap.get(record.token); if (win != null && win.mActivityRecord == record) { if (DEBUG) Log.d(TAG, "getWindowState win = " + win.mActivityRecord); return win; } // 方法2:遍历所有窗口(备选方案) for (WindowState ws : wms.mWindowMap.values()) { if (DEBUG) Log.d(TAG, "getWindowState ws = " + ws.mActivityRecord); if (ws.mActivityRecord == record) { return ws; } } return null; } } // 注册主屏窗口 public void registerPrimaryWindow(WindowState win) { mPrimaryWindow = win; if (DEBUG) Log.d(TAG, "Registered primary window: " + win); } public void registerSecondaryWindow(WindowState win) { mSecondaryWindow = win; if (DEBUG) Log.d(TAG, "Registered secondary window: " + win); } // 处理焦点变化(确保只有一个窗口获得焦点) public void handleFocusChange(WindowState focused) { if (DEBUG) Log.d(TAG, "handleFocusChange"); if (focused == null) return; if (focused == mPrimaryWindow && mSecondaryWindow != null) { //mSecondaryWindow.onSetFocused(false); // 取消副屏焦点 //focused.mWmService.mInputMonitor.setInputFocusLw(mSecondaryWindow, false); mSecondaryWindow.getDisplayContent().getInputMonitor().setInputFocusLw(mSecondaryWindow, false); } else if (focused == mSecondaryWindow && mPrimaryWindow != null) { //mPrimaryWindow.onSetFocused(false); // 取消主屏焦点 //focused.mWmService.mInputMonitor.setInputFocusLw(mPrimaryWindow, false); mPrimaryWindow.getDisplayContent().getInputMonitor().setInputFocusLw(mPrimaryWindow, false); } focused.mWmService.updateFocusedWindowLocked( WindowManagerService.UPDATE_FOCUS_NORMAL, true ); } // 添加窗口令牌映射 /* private final ArrayMap<IBinder, ActivityRecord> mTokenToRecord = new ArrayMap<>(); public void registerWindowToken(IBinder token, ActivityRecord ar) { mTokenToRecord.put(token, ar); } public ActivityRecord getRecordForToken(IBinder token) { return mTokenToRecord.get(token); } */ // 添加生命周期监听器 public void addLifecycleListener(LifecycleListener listener) { if (DEBUG) Log.d(TAG, "addLifecycleListener"); mLifecycleListeners.add(listener); } // 状态变化通知 public void onStateChanged(ActivityRecord activity, State state) { if (DEBUG) Log.d(TAG, "onStateChanged"); for (LifecycleListener listener : mLifecycleListeners) { listener.onStateChanged(activity, state); } } public void onDestroyed(ActivityRecord activity) { if (DEBUG) Log.d(TAG, "onDestroyed"); for (LifecycleListener listener : mLifecycleListeners) { listener.onDestroyed(activity); } if (activity == mPrimaryActivity || activity == mSecondaryActivity) { sSessions.remove(mTaskId); } } public void onConfigurationChanged(ActivityRecord activity, Configuration newConfig) { if (DEBUG) Log.d(TAG, "onConfigurationChanged"); for (LifecycleListener listener : mLifecycleListeners) { listener.onConfigurationChanged(activity, newConfig); } } // 添加此方法用于调试 public void dumpVisibilityState() { Log.d(TAG, "Primary Activity Visibility: " + (mPrimaryActivity != null ? mPrimaryActivity.isVisible() : "null")); Log.d(TAG, "Secondary Activity Visibility: " + (mSecondaryActivity != null ? mSecondaryActivity.isVisible() : "null")); Log.d(TAG, "Primary Window Visibility: " + (mPrimaryWindow != null ? mPrimaryWindow.isVisible() : "null")); Log.d(TAG, "Secondary Window Visibility: " + (mSecondaryWindow != null ? mSecondaryWindow.isVisible() : "null")); } // 销毁会话 public void destroy() { sSessions.remove(mTaskId); Log.i(TAG, "销毁平行会话,任务ID: " + mTaskId); } // 获取指定任务的会话 public static ParallelSession getSessionForTask(int taskId) { if (DEBUG) Log.d(TAG, "getSessionForTask = "+taskId); return sSessions.get(taskId); } public static void addSession(int taskId, ParallelSession session) { sSessions.put(taskId, session); } public static boolean isParallelSessionActive(int taskId) { if (DEBUG) Log.d(TAG, "isParallelSessionActive = "+taskId); return sSessions.get(taskId) != null; } public ActivityRecord getPrimaryActivity() { if (DEBUG) Log.d(TAG, "getPrimaryActivity = "+mPrimaryActivity); dumpVisibilityState(); return mPrimaryActivity; } public ActivityRecord getSecondaryActivity() { if (DEBUG) Log.d(TAG, "getSecondaryActivity = "+mSecondaryActivity); return mSecondaryActivity; } public WindowState getPrimaryWindow() { if (DEBUG) Log.d(TAG, "getPrimaryWindow = "+mPrimaryWindow); return mPrimaryWindow; } public WindowState getSecondaryWindow() { if (DEBUG) Log.d(TAG, "getSecondaryWindow = "+mSecondaryWindow); return mSecondaryWindow; } /* public interface ActivityLifecycleListener { void onStateChanged(ActivityRecord activity, State state); default void onDestroyed(ActivityRecord activity); void onConfigurationChanged(ActivityRecord activity, Configuration newConfig); } */ /** * 平行视界完整工作流程 入口触发:当主Activity启动副Activity时,ActivityStarter 检测到白名单匹配 会话创建:创建 ParallelSession 并关联主Activity 副屏创建:创建副屏任务栈,将目标Activity放入副屏 布局阶段:DisplayPolicy 为两个Activity计算分屏布局 输入路由:InputDispatcher 根据触摸位置分发到正确窗口 生命周期同步:通过监听器实现主副屏状态同步 新增 ParallelSession.java 新增类 会话管理核心 管理活动、窗口、布局和生命周期同步 DisplayPolicy.java 修改 layoutWindowLw() 方法 覆盖布局逻辑,应用平行视界布局 WindowManagerService.java 修改 添加 ParallelInputMonitor 处理触摸事件重定向 WindowState.java 修改 onSetFocused() 和 attach() 处理焦点管理和窗口注册 ActivityRecord.java 修改 生命周期方法覆盖 实现状态同步和配置变更通知 ActivityStarter.java 修改 execute() 方法 添加平行会话启动逻辑 新增 /system/etc/parallel_apps.xml 配置文件 应用配置列表 定义支持平行视界的应用及其分屏比例 */ }这是安卓14修改类似中兴平行视界的类,改完后副屏打开之后,主屏会消失不显示是什么原因,怎么解决;以及副屏幕返回之后,主屏幕一起退出了,如何修改
最新发布
08-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值