зеркало из https://github.com/mozilla/pjs.git
Bug 703601 - Fix a bunch of lifecycle issues with Flash on Android
This commit is contained in:
Родитель
4df1112727
Коммит
5c757c809c
|
@ -90,6 +90,7 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin)
|
|||
#ifdef MOZ_WIDGET_ANDROID
|
||||
mSurface(nsnull),
|
||||
mANPDrawingModel(0),
|
||||
mOnScreen(true),
|
||||
#endif
|
||||
mRunning(NOT_STARTED),
|
||||
mWindowless(false),
|
||||
|
@ -724,6 +725,44 @@ void nsNPAPIPluginInstance::SetEventModel(NPEventModel aModel)
|
|||
#endif
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
|
||||
static void SendLifecycleEvent(nsNPAPIPluginInstance* aInstance, PRUint32 aAction)
|
||||
{
|
||||
ANPEvent event;
|
||||
event.inSize = sizeof(ANPEvent);
|
||||
event.eventType = kLifecycle_ANPEventType;
|
||||
event.data.lifecycle.action = aAction;
|
||||
aInstance->HandleEvent(&event, nsnull);
|
||||
}
|
||||
|
||||
void nsNPAPIPluginInstance::NotifyForeground(bool aForeground)
|
||||
{
|
||||
PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetForeground this=%p\n foreground=%d",this, aForeground));
|
||||
if (RUNNING != mRunning)
|
||||
return;
|
||||
|
||||
SendLifecycleEvent(this, aForeground ? kResume_ANPLifecycleAction : kPause_ANPLifecycleAction);
|
||||
}
|
||||
|
||||
void nsNPAPIPluginInstance::NotifyOnScreen(bool aOnScreen)
|
||||
{
|
||||
PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetOnScreen this=%p\n onScreen=%d",this, aOnScreen));
|
||||
if (RUNNING != mRunning || mOnScreen == aOnScreen)
|
||||
return;
|
||||
|
||||
mOnScreen = aOnScreen;
|
||||
SendLifecycleEvent(this, aOnScreen ? kOnScreen_ANPLifecycleAction : kOffScreen_ANPLifecycleAction);
|
||||
}
|
||||
|
||||
void nsNPAPIPluginInstance::MemoryPressure()
|
||||
{
|
||||
PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::MemoryPressure this=%p\n",this));
|
||||
if (RUNNING != mRunning)
|
||||
return;
|
||||
|
||||
SendLifecycleEvent(this, kFreeMemory_ANPLifecycleAction);
|
||||
}
|
||||
|
||||
void nsNPAPIPluginInstance::SetANPDrawingModel(PRUint32 aModel)
|
||||
{
|
||||
mANPDrawingModel = aModel;
|
||||
|
|
|
@ -147,6 +147,14 @@ public:
|
|||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
void NotifyForeground(bool aForeground);
|
||||
void NotifyOnScreen(bool aOnScreen);
|
||||
void MemoryPressure();
|
||||
|
||||
bool IsOnScreen() {
|
||||
return mOnScreen;
|
||||
}
|
||||
|
||||
PRUint32 GetANPDrawingModel() { return mANPDrawingModel; }
|
||||
void SetANPDrawingModel(PRUint32 aModel);
|
||||
|
||||
|
@ -282,6 +290,7 @@ private:
|
|||
bool mUsePluginLayersPref;
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
void* mSurface;
|
||||
bool mOnScreen;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -375,6 +375,10 @@ nsPluginHost::nsPluginHost()
|
|||
if (obsService) {
|
||||
obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
obsService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, false);
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
obsService->AddObserver(this, "application-foreground", false);
|
||||
obsService->AddObserver(this, "application-background", false);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PLUGIN_LOGGING
|
||||
|
@ -3381,6 +3385,24 @@ NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject,
|
|||
mInstances[i]->PrivateModeStateChanged();
|
||||
}
|
||||
}
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
if (!nsCRT::strcmp("application-background", aTopic)) {
|
||||
for(PRUint32 i = 0; i < mInstances.Length(); i++) {
|
||||
mInstances[i]->NotifyForeground(false);
|
||||
}
|
||||
}
|
||||
if (!nsCRT::strcmp("application-foreground", aTopic)) {
|
||||
for(PRUint32 i = 0; i < mInstances.Length(); i++) {
|
||||
if (mInstances[i]->IsOnScreen())
|
||||
mInstances[i]->NotifyForeground(true);
|
||||
}
|
||||
}
|
||||
if (!nsCRT::strcmp("memory-pressure", aTopic)) {
|
||||
for(PRUint32 i = 0; i < mInstances.Length(); i++) {
|
||||
mInstances[i]->MemoryPressure();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -339,9 +339,8 @@ nsPluginInstanceOwner::nsPluginInstanceOwner()
|
|||
mWaitingForPaint = false;
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
mOnScreen = false;
|
||||
mInverted = false;
|
||||
mLayer = new AndroidMediaLayer();
|
||||
mLayer = nsnull;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -393,10 +392,7 @@ nsPluginInstanceOwner::~nsPluginInstanceOwner()
|
|||
mPluginWindow = nsnull;
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
if (mLayer) {
|
||||
delete mLayer;
|
||||
mLayer = nsnull;
|
||||
}
|
||||
RemovePluginView();
|
||||
#endif
|
||||
|
||||
if (mInstance) {
|
||||
|
@ -1688,22 +1684,6 @@ void nsPluginInstanceOwner::SendSize(int width, int height)
|
|||
mInstance->HandleEvent(&event, nsnull);
|
||||
}
|
||||
|
||||
void nsPluginInstanceOwner::SendOnScreenEvent(bool onScreen)
|
||||
{
|
||||
if (!mInstance)
|
||||
return;
|
||||
|
||||
if ((onScreen && !mOnScreen) || (!onScreen && mOnScreen)) {
|
||||
ANPEvent event;
|
||||
event.inSize = sizeof(ANPEvent);
|
||||
event.eventType = kLifecycle_ANPEventType;
|
||||
event.data.lifecycle.action = onScreen ? kOnScreen_ANPLifecycleAction : kOffScreen_ANPLifecycleAction;
|
||||
mInstance->HandleEvent(&event, nsnull);
|
||||
|
||||
mOnScreen = onScreen;
|
||||
}
|
||||
}
|
||||
|
||||
bool nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect)
|
||||
{
|
||||
void* javaSurface = mInstance->GetJavaSurface();
|
||||
|
@ -1754,14 +1734,12 @@ bool nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect)
|
|||
aRect.height);
|
||||
#endif
|
||||
|
||||
SendOnScreenEvent(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void nsPluginInstanceOwner::RemovePluginView()
|
||||
{
|
||||
if (!mInstance || !mObjectFrame | !mOnScreen)
|
||||
if (!mInstance || !mObjectFrame)
|
||||
return;
|
||||
|
||||
void* surface = mInstance->GetJavaSurface();
|
||||
|
@ -1779,7 +1757,6 @@ void nsPluginInstanceOwner::RemovePluginView()
|
|||
"removePluginView",
|
||||
"(Landroid/view/View;)V");
|
||||
env->CallStaticVoidMethod(cls, method, surface);
|
||||
SendOnScreenEvent(false);
|
||||
}
|
||||
|
||||
void nsPluginInstanceOwner::Invalidate() {
|
||||
|
@ -2759,6 +2736,14 @@ nsPluginInstanceOwner::Destroy()
|
|||
mContent->RemoveEventListener(NS_LITERAL_STRING("text"), this, true);
|
||||
#endif
|
||||
|
||||
#if MOZ_WIDGET_ANDROID
|
||||
RemovePluginView();
|
||||
|
||||
if (mLayer)
|
||||
mLayer->SetVisible(false);
|
||||
|
||||
#endif
|
||||
|
||||
if (mWidget) {
|
||||
if (mPluginWindow) {
|
||||
mPluginWindow->SetPluginWidget(nsnull);
|
||||
|
@ -2867,7 +2852,7 @@ void nsPluginInstanceOwner::Paint(gfxContext* aContext,
|
|||
const gfxRect& aFrameRect,
|
||||
const gfxRect& aDirtyRect)
|
||||
{
|
||||
if (!mInstance || !mObjectFrame)
|
||||
if (!mInstance || !mObjectFrame || !mPluginDocumentActiveState)
|
||||
return;
|
||||
|
||||
PRInt32 model = mInstance->GetANPDrawingModel();
|
||||
|
@ -2880,11 +2865,13 @@ void nsPluginInstanceOwner::Paint(gfxContext* aContext,
|
|||
}
|
||||
|
||||
if (model == kOpenGL_ANPDrawingModel) {
|
||||
if (!mLayer)
|
||||
mLayer = new AndroidMediaLayer();
|
||||
|
||||
// FIXME: this is gross
|
||||
float zoomLevel = aFrameRect.width / (float)mPluginWindow->width;
|
||||
mLayer->UpdatePosition(aFrameRect, zoomLevel);
|
||||
|
||||
SendOnScreenEvent(true);
|
||||
SendSize((int)aFrameRect.width, (int)aFrameRect.height);
|
||||
return;
|
||||
}
|
||||
|
@ -3587,17 +3574,6 @@ void nsPluginInstanceOwner::UpdateWindowPositionAndClipRect(bool aSetWindow)
|
|||
} else {
|
||||
mPluginWindow->clipRect.right = 0;
|
||||
mPluginWindow->clipRect.bottom = 0;
|
||||
#if 0 //MOZ_WIDGET_ANDROID
|
||||
if (mInstance) {
|
||||
PRInt32 model = mInstance->GetANPDrawingModel();
|
||||
|
||||
if (model == kSurface_ANPDrawingModel) {
|
||||
RemovePluginView();
|
||||
} else if (model == kOpenGL_ANPDrawingModel) {
|
||||
HidePluginLayer();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!aSetWindow)
|
||||
|
@ -3625,6 +3601,26 @@ nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive)
|
|||
{
|
||||
mPluginDocumentActiveState = aIsActive;
|
||||
UpdateWindowPositionAndClipRect(true);
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
if (mInstance) {
|
||||
if (mLayer)
|
||||
mLayer->SetVisible(mPluginDocumentActiveState);
|
||||
|
||||
if (!mPluginDocumentActiveState)
|
||||
RemovePluginView();
|
||||
|
||||
mInstance->NotifyOnScreen(mPluginDocumentActiveState);
|
||||
|
||||
// This is, perhaps, incorrect. It is supposed to be sent
|
||||
// when "the webview has paused or resumed". The side effect
|
||||
// is that Flash video players pause or resume (if they were
|
||||
// playing before) based on the value here. I personally think
|
||||
// we want that on Android when switching to another tab, so
|
||||
// that's why we call it here.
|
||||
mInstance->NotifyForeground(mPluginDocumentActiveState);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // XP_MACOSX
|
||||
|
||||
|
|
|
@ -328,16 +328,14 @@ private:
|
|||
void FixUpURLS(const nsString &name, nsAString &value);
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
void SendSize(int width, int height);
|
||||
void SendOnScreenEvent(bool onScreen);
|
||||
|
||||
bool AddPluginView(const gfxRect& aRect);
|
||||
void RemovePluginView();
|
||||
|
||||
bool mOnScreen;
|
||||
bool mInverted;
|
||||
|
||||
// For kOpenGL_ANPDrawingModel
|
||||
mozilla::AndroidMediaLayer *mLayer;
|
||||
nsRefPtr<mozilla::AndroidMediaLayer> mLayer;
|
||||
#endif
|
||||
|
||||
nsPluginNativeWindow *mPluginWindow;
|
||||
|
|
|
@ -1507,7 +1507,8 @@ abstract public class GeckoApp
|
|||
if (tab == null)
|
||||
return;
|
||||
|
||||
tab.removePluginLayer(surface);
|
||||
Layer layer = tab.removePluginLayer(surface);
|
||||
hidePluginLayer(layer);
|
||||
}
|
||||
|
||||
public void showSurface(Surface surface, int x, int y,
|
||||
|
@ -2087,7 +2088,7 @@ abstract public class GeckoApp
|
|||
Runnable r = new SessionSnapshotRunnable(null);
|
||||
GeckoAppShell.getHandler().post(r);
|
||||
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createPauseEvent());
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createPauseEvent(mOwnActivityDepth));
|
||||
// The user is navigating away from this activity, but nothing
|
||||
// has come to the foreground yet; for Gecko, we may want to
|
||||
// stop repainting, for example.
|
||||
|
@ -2107,7 +2108,8 @@ abstract public class GeckoApp
|
|||
{
|
||||
Log.i(LOGTAG, "resume");
|
||||
if (checkLaunchState(LaunchState.GeckoRunning))
|
||||
GeckoAppShell.onResume();
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createResumeEvent(mOwnActivityDepth));
|
||||
|
||||
// After an onPause, the activity is back in the foreground.
|
||||
// Undo whatever we did in onPause.
|
||||
super.onResume();
|
||||
|
@ -2156,7 +2158,7 @@ abstract public class GeckoApp
|
|||
// etc., and generally mark the profile as 'clean', and then
|
||||
// dirty it again if we get an onResume.
|
||||
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createStoppingEvent());
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createStoppingEvent(mOwnActivityDepth));
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
|
@ -2173,7 +2175,7 @@ abstract public class GeckoApp
|
|||
Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - onStart");
|
||||
|
||||
Log.i(LOGTAG, "start");
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createStartEvent());
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createStartEvent(mOwnActivityDepth));
|
||||
super.onStart();
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@ public class GeckoEvent {
|
|||
private static final int VISITED = 21;
|
||||
private static final int NETWORK_CHANGED = 22;
|
||||
private static final int PROXIMITY_EVENT = 23;
|
||||
private static final int ACTIVITY_RESUMING = 24;
|
||||
|
||||
public static final int IME_COMPOSITION_END = 0;
|
||||
public static final int IME_COMPOSITION_BEGIN = 1;
|
||||
|
@ -139,16 +140,28 @@ public class GeckoEvent {
|
|||
mType = evType;
|
||||
}
|
||||
|
||||
public static GeckoEvent createPauseEvent() {
|
||||
return new GeckoEvent(ACTIVITY_PAUSING);
|
||||
public static GeckoEvent createPauseEvent(int activityDepth) {
|
||||
GeckoEvent event = new GeckoEvent(ACTIVITY_PAUSING);
|
||||
event.mFlags = activityDepth > 0 ? 1 : 0;
|
||||
return event;
|
||||
}
|
||||
|
||||
public static GeckoEvent createStoppingEvent() {
|
||||
return new GeckoEvent(ACTIVITY_STOPPING);
|
||||
public static GeckoEvent createResumeEvent(int activityDepth) {
|
||||
GeckoEvent event = new GeckoEvent(ACTIVITY_RESUMING);
|
||||
event.mFlags = activityDepth > 0 ? 1 : 0;
|
||||
return event;
|
||||
}
|
||||
|
||||
public static GeckoEvent createStartEvent() {
|
||||
return new GeckoEvent(ACTIVITY_START);
|
||||
public static GeckoEvent createStoppingEvent(int activityDepth) {
|
||||
GeckoEvent event = new GeckoEvent(ACTIVITY_STOPPING);
|
||||
event.mFlags = activityDepth > 0 ? 1 : 0;
|
||||
return event;
|
||||
}
|
||||
|
||||
public static GeckoEvent createStartEvent(int activityDepth) {
|
||||
GeckoEvent event = new GeckoEvent(ACTIVITY_START);
|
||||
event.mFlags = activityDepth > 0 ? 1 : 0;
|
||||
return event;
|
||||
}
|
||||
|
||||
public static GeckoEvent createShutdownEvent() {
|
||||
|
|
|
@ -547,6 +547,14 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj)
|
|||
break;
|
||||
}
|
||||
|
||||
case ACTIVITY_STOPPING:
|
||||
case ACTIVITY_START:
|
||||
case ACTIVITY_PAUSING:
|
||||
case ACTIVITY_RESUMING: {
|
||||
mFlags = jenv->GetIntField(jobj, jFlagsField);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -569,6 +569,7 @@ public:
|
|||
VISITED = 21,
|
||||
NETWORK_CHANGED = 22,
|
||||
PROXIMITY_EVENT = 23,
|
||||
ACTIVITY_RESUMING = 24,
|
||||
dummy_java_enum_list_end
|
||||
};
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
namespace mozilla {
|
||||
|
||||
AndroidMediaLayer::AndroidMediaLayer()
|
||||
: mInverted(false) {
|
||||
: mInverted(false), mVisible(true) {
|
||||
}
|
||||
|
||||
AndroidMediaLayer::~AndroidMediaLayer() {
|
||||
|
@ -132,6 +132,8 @@ void AndroidMediaLayer::SetNativeWindowDimensions(void* aWindow, const gfxRect&
|
|||
}
|
||||
|
||||
void AndroidMediaLayer::UpdatePosition(const gfxRect& aRect, float aZoomLevel) {
|
||||
if (!mVisible)
|
||||
return;
|
||||
|
||||
std::map<void*, SurfaceData*>::iterator it;
|
||||
|
||||
|
@ -152,4 +154,24 @@ void AndroidMediaLayer::UpdatePosition(const gfxRect& aRect, float aZoomLevel) {
|
|||
}
|
||||
}
|
||||
|
||||
void AndroidMediaLayer::SetVisible(bool aVisible) {
|
||||
if (aVisible == mVisible)
|
||||
return;
|
||||
|
||||
mVisible = aVisible;
|
||||
if (mVisible)
|
||||
return;
|
||||
|
||||
// Hide all surfaces
|
||||
std::map<void*, SurfaceData*>::iterator it;
|
||||
|
||||
if (EnsureContentSurface())
|
||||
AndroidBridge::Bridge()->HideSurface(mContentData.surface);
|
||||
|
||||
for (it = mVideoSurfaces.begin(); it != mVideoSurfaces.end(); it++) {
|
||||
SurfaceData* data = it->second;
|
||||
AndroidBridge::Bridge()->HideSurface(data->surface);
|
||||
}
|
||||
}
|
||||
|
||||
} /* mozilla */
|
||||
|
|
|
@ -41,15 +41,17 @@
|
|||
#include <map>
|
||||
#include <jni.h>
|
||||
#include "gfxRect.h"
|
||||
#include "nsISupports.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AndroidMediaLayer
|
||||
{
|
||||
public:
|
||||
|
||||
AndroidMediaLayer();
|
||||
virtual ~AndroidMediaLayer();
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(AndroidMediaLayer)
|
||||
|
||||
void* GetNativeWindowForContent();
|
||||
|
||||
|
@ -68,8 +70,15 @@ public:
|
|||
mInverted = aInverted;
|
||||
}
|
||||
|
||||
bool IsVisible() {
|
||||
return mVisible;
|
||||
}
|
||||
|
||||
void SetVisible(bool aVisible);
|
||||
|
||||
private:
|
||||
bool mInverted;
|
||||
bool mVisible;
|
||||
|
||||
class SurfaceData {
|
||||
public:
|
||||
|
|
|
@ -370,6 +370,9 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
|
|||
}
|
||||
|
||||
case AndroidGeckoEvent::ACTIVITY_STOPPING: {
|
||||
if (curEvent->Flags() > 0)
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsIObserverService> obsServ =
|
||||
mozilla::services::GetObserverService();
|
||||
NS_NAMED_LITERAL_STRING(minimize, "heap-minimize");
|
||||
|
@ -395,6 +398,14 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
|
|||
}
|
||||
|
||||
case AndroidGeckoEvent::ACTIVITY_PAUSING: {
|
||||
if (curEvent->Flags() == 0) {
|
||||
// We aren't transferring to one of our own activities, so set
|
||||
// background status
|
||||
nsCOMPtr<nsIObserverService> obsServ =
|
||||
mozilla::services::GetObserverService();
|
||||
obsServ->NotifyObservers(nsnull, "application-background", nsnull);
|
||||
}
|
||||
|
||||
// We really want to send a notification like profile-before-change,
|
||||
// but profile-before-change ends up shutting some things down instead
|
||||
// of flushing data
|
||||
|
@ -413,6 +424,9 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
|
|||
}
|
||||
|
||||
case AndroidGeckoEvent::ACTIVITY_START: {
|
||||
if (curEvent->Flags() > 0)
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsIObserverService> obsServ =
|
||||
mozilla::services::GetObserverService();
|
||||
obsServ->NotifyObservers(nsnull, "application-foreground", nsnull);
|
||||
|
@ -483,6 +497,17 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
|
|||
break;
|
||||
}
|
||||
|
||||
case AndroidGeckoEvent::ACTIVITY_RESUMING: {
|
||||
if (curEvent->Flags() == 0) {
|
||||
// We didn't return from one of our own activities, so restore
|
||||
// to foreground status
|
||||
nsCOMPtr<nsIObserverService> obsServ =
|
||||
mozilla::services::GetObserverService();
|
||||
obsServ->NotifyObservers(nsnull, "application-foreground", nsnull);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
nsWindow::OnGlobalAndroidEvent(curEvent);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче